Джексон: несколько сериализаторов на одной и той же сущности, когда вызываются разные Rest EndPoint - PullRequest
0 голосов
/ 21 апреля 2020

Я стараюсь избегать использования антипаттерна DTO, когда вызываются разные EndPoint, где каждый возвращает отдельное представление одной и той же сущности. Я хотел бы воспользоваться сериализацией, которую выполняет Джексон, когда я возвращаю сущность в Rest EndPoint. Это означает, что сериализация выполняется только один раз, а не дважды, как это было бы с DTO (объект для DTO и DTO для Json):

Пример EndPoints:

@GetMapping("/events")
public ResponseEntity<List<Event>> getAllEvents(){
    try {
        List<Event> events = (List<Event>) eventsRepository.findAll();
        return new ResponseEntity<List<Event>>(
                events, HttpStatus.OK);
    }catch(IllegalArgumentException e) {
        return new ResponseEntity<List<Event>>(HttpStatus.BAD_REQUEST);
    }
}

@GetMapping("/events/{code}")
public ResponseEntity<Event> retrieveEvent(@PathVariable String code){
    Optional<Event> event = eventsRepository.findByCode(code);
    return event.isPresent() ? 
            new ResponseEntity<Event>(event.get(), HttpStatus.OK) :
            new ResponseEntity<Event>(HttpStatus.BAD_REQUEST);
}

Сериализатор (класс, который расширяет StdSerializer):

@Override
public void serialize(Event value, JsonGenerator gen, 
        SerializerProvider provider) throws IOException {

    if(firstRepresentation) {
        //First Representation
        gen.writeStartObject();
        gen.writeNumberField("id", value.getId());
        gen.writeObjectField("creation", value.getCreation());

        gen.writeObjectFieldStart("event_tracks");
        for (EventTrack eventTrack : value.getEventsTracks()) {

            gen.writeNumberField("id", eventTrack.getId());
            gen.writeObjectField("startTime", eventTrack.getStartTime());
            gen.writeObjectField("endTime", eventTrack.getEndTime());
            gen.writeNumberField("priority", eventTrack.getPriority());

            gen.writeObjectFieldStart("user");
            gen.writeNumberField("id", eventTrack.getUser().getId());
            gen.writeEndObject();

            gen.writeObjectFieldStart("state");
            gen.writeNumberField("id", eventTrack.getState().getId());
            gen.writeStringField("name", eventTrack.getState().getName());
            gen.writeEndObject();

        }

        gen.writeEndObject();
        gen.writeEndObject();
    }else if(secondRepresentation) {
       //Second Representation
    }
}

Сущность:

@JsonSerialize(using = EventSerializer.class)
@RequiredArgsConstructor
@Getter
@Setter
public class Event implements Comparable<Event>{

    private Long id;

    @JsonIgnore
    private String code;

    private Timestamp creation;

    @NonNull
    private String description;

    @JsonUnwrapped
    @NonNull
    private EventSource eventSource;

    @NonNull
    private String title;

    @NonNull
    private Category category;

    @NonNull
    @JsonProperty("event_tracks")
    private List<EventTrack> eventsTracks;

    @JsonProperty("protocol_tracks")
    private List<ProtocolTrack> protocolTracks;

    public void addEventTrack(@NonNull EventTrack eventTracks) {
        eventsTracks.add(eventTracks);
    }

    @JsonIgnore
    public EventTrack getLastEventTrack() {
        return eventsTracks.get(eventsTracks.size() - 1);
    }

    @JsonIgnore
    public int getLastPriority() {
        return getLastEventTrack().getPriority();
    }

    public void generateUUIDCode() {
        this.code = UUID.randomUUID().toString();
    }

    @Override
    public int compareTo(Event o) {
        return this.getLastPriority() - o.getLastPriority();
    }
}

Итак, пока я удалось сериализовать тип представления с помощью класса, расширяющего StdDeserializer, но это не дает мне гибкости для расширения представлений одних и тех же атрибутов сущности несколькими способами. Хотя я пробовал это с аннотациями Json, но я понимаю, что чем больше представлений у класса сущностей, тем он может быть очень сложным, чем просто. Может быть, какая-то идея, как я мог это сделать.

Спасибо.

1 Ответ

1 голос
/ 21 апреля 2020

Если вы хотите определить несколько представлений одного и того же компонента, вы можете использовать Jackson JsonView.

. С представлениями json вы можете установить различные стратегии, чтобы определить, какое свойство будет сериализовано в ответе, и так используйте разные views по конечной точке.

Документация здесь: https://www.baeldung.com/jackson-json-view-annotation

Только не забывайте, что вы делаете REST здесь .... избегайте выставлять слишком много представления одного и того же ресурса

...