升级至Jersey 3.1.0后响应丢失子类字段,该如何处理?
Jersey 3.1.0返回子类字段缺失的解决方案
问题背景
Tomcat升级后同步将Jersey从3.0.2升级至3.1.0,发现REST接口返回JSON时,子类Display2的bar字段未被序列化,仅返回父类Display的foo字段。该接口在Jersey 2.*及3.0.2版本中可正常返回全部字段。
相关代码:
class Display { int foo; public int getFoo() { ... } } class Display2 extends Display { int bar; public int getBar() {...} } @POST @Path("/move") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.APPLICATION_JSON) public Display move(....) { Display x= new Display2(...); return x; }
原因分析
Jersey 3.1.0升级了依赖的Jackson版本(多为Jackson 2.15+),其默认的类型序列化策略发生变更:默认仅序列化接口声明的返回类型(Display)的字段,而非实际实例的类型(Display2)字段。
解决方案
方案1:修改接口返回类型为子类
直接将接口的返回类型改为Display2,让序列化器明确按实际类型处理:
@POST @Path("/move") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.APPLICATION_JSON) public Display2 move(....) { Display2 x= new Display2(...); return x; }
方案2:配置Jackson序列化策略
若无法修改返回类型,可通过自定义Jackson配置强制序列化实际类型的字段:
@Provider public class JacksonConfig implements ContextResolver<ObjectMapper> { private final ObjectMapper mapper; public JacksonConfig() { mapper = new ObjectMapper(); // 启用默认类型处理,序列化实际对象的所有字段 mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); } @Override public ObjectMapper getContext(Class<?> type) { return mapper; } }
注册该配置类到Jersey的应用中,即可让Jackson序列化实际实例的全部字段。
方案3:添加Jackson类型注解
在父类Display上添加类型注解,指定序列化时包含子类信息:
import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonSubTypes; @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type" ) @JsonSubTypes({ @JsonSubTypes.Type(value = Display2.class, name = "display2") }) class Display { int foo; public int getFoo() { ... } } class Display2 extends Display { int bar; public int getBar() {...} }
此方式会在JSON中添加类型标识字段(如"type":"display2"),同时序列化子类的所有字段。
内容的提问来源于stack exchange,提问作者Vladimir Menkov
相关产品推荐
相关产品推荐

