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....避免公开同一资源的太多表示
我试图避免在调用不同的 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....避免公开同一资源的太多表示