使用Spring和JsonTypeInfo注释将JSON反序列化为多态对象模型

gri*_*ori 25 java spring json jackson

我的Spring MVC(v3.2.0.RELEASE)Web应用程序中有以下对象模型:

public class Order {
  private Payment payment;
}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = As.WRAPPER_OBJECT)
@JsonSubTypes.Type(name = "creditCardPayment", value = CreditCardPayment.class)
public interface Payment {}


@JsonTypeName("creditCardPayment")
public class CreditCardPayment implements Payment {}
Run Code Online (Sandbox Code Playgroud)

当我将Order类序列化为JSON时,我得到以下结果(这正是我想要的):

{
  "payment" : {
    "creditCardPayment": {
      ...
    } 
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,如果我使用上面的JSON并尝试将其反序列化回我的对象​​模型,我会得到以下异常:

无法读取JSON:无法解析类型ID"类:CreditCardPayment"变成[简单类型,类的付款]在[来源的子类型:org.apache.catalina.connector.CoyoteInputStream@19629355; line:1,column:58](通过参考链:订单["付款"]); 嵌套异常是com.fasterxml.jackson.databind.JsonMappingException:无法解析类型ID"类:CreditCardPayment"变成[简单类型,类的付款]在[来源的子类型:org.apache.catalina.connector.CoyoteInputStream@19629355; line:1,column:58](通过参考链:订单["付款"])

我的应用程序是通过Spring JavaConf配置的,如下所示:

@Configuration
@EnableWebMvc
public class AppWebConf extends WebMvcConfigurerAdapter {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializationInclusion(Include.NON_NULL);
        objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);
        return objectMapper;
    }

    @Bean
    public MappingJackson2HttpMessageConverter mappingJacksonMessageConverter() {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setObjectMapper(objectMapper());
        return converter;
    }

    @Bean
    public Jaxb2RootElementHttpMessageConverter jaxbMessageConverter() {
        return new Jaxb2RootElementHttpMessageConverter();
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(jaxbMessageConverter());
        converters.add(mappingJacksonMessageConverter());
    }
}
Run Code Online (Sandbox Code Playgroud)

为了测试,我有一个带有2个方法的控制器,一个返回一个订单用于HTTP GET请求(这个工作)和一个通过HTTP POST接受订单(这个失败),例如

@Controller
public class TestController {

    @ResponseBody
    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public Order getTest() {}

    @RequestMapping(value = "/test", method = RequestMethod.POST)
    public void postTest(@RequestBody order) {}

}
Run Code Online (Sandbox Code Playgroud)

我已经尝试了关于SO的各种讨论的所有建议,但到目前为止没有运气.谁能发现我做错了什么?

rag*_*nor 12

尝试使用ObjectMapper.registerSubtypes而不是使用注释来注册子类型

  • 我遇到了同样的问题,上面的解决方案没有帮助. (6认同)
  • 那很有效!我从`Payment`接口删除了`@JsonSubTypes.Type(name ="creditCardPayment",value = CreditCardPayment.class)`并在`AppWebConf`类中添加了`objectMapper.registerSubtypes(CreditCardPayment.class);`.令人失望的是,注释不起作用,因为我想保持我的配置通用,但至少它让我超越了这个问题.谢谢. (2认同)

Ras*_*avi 5

该方法registerSubtypes()有效!

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type")
public interface Geometry {
  //...
}

public class Point implements Geometry{
  //...
}
public class Polygon implements Geometry{
  //...
}
public class LineString implements Geometry{
  //...
}

GeoJson geojson= null;
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.registerSubtypes(Polygon.class,LineString.class,Point.class);

try {
    geojson=mapper.readValue(source, GeoJson.class);            
} catch (IOException e) {
    e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)

注意1:我们使用接口和实现类。如果要让杰克逊按照实现类反序列化这些类,则必须使用ObjectMapper的“ registerSubtypes”方法注册所有这些类。

注意2:此外,您还可以在接口中使用“ @JsonTypeInfo(use = JsonTypeInfo.Id.NAME,include = JsonTypeInfo.As.PROPERTY,property =“ type”)“作为注释。

当mapper将POJO的值作为json写入时,您还可以定义属性的顺序。

您可以使用以下注释来做到这一点。

@JsonPropertyOrder({"type","crs","version","features"})
public class GeoJson {

    private String type="FeatureCollection";
    private List<Feature> features;
    private String version="1.0.0";
    private CRS crs = new CRS();
    ........
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!