Jackson:当调用不同的 Rest EndPoint 时,同一实体上的多个序列化程序

Jackson: Multiple Serializers on the same entity when differents Rest EndPoint are called

我试图避免在调用不同的 EndPoint 时使用 DTO 反模式,其中每个 return 都是同一实体的不同表示。当我 return Rest EndPoint 中的实体时,我想利用 Jackson 执行的序列化。这意味着序列化只进行一次,而不是像使用 DTO 那样进行两次(实体到 DTO 和 DTO 到 Json):

端点示例:

@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);
}

序列化器(class 扩展 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 的 class 来序列化表示类型,但这并没有给我在多个相同实体属性的表示中扩展的灵活性方法。虽然我已经尝试过使用 Json 注释,但我意识到实体 class 具有的表示越多,它就会变得非常复杂,而这本来应该很简单。也许知道我该怎么做。

谢谢。

如果你想定义同一个 bean 的多个表示,你可以使用 Jackson JsonView

使用 json 视图,您可以设置不同的策略来定义哪些 属性 将在响应中序列化,因此端点使用不同的 views

文档在这里:https://www.baeldung.com/jackson-json-view-annotation

只是不要忘记你在这里做 REST....避免公开同一资源的太多表示