我的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 {}
当我将Order类序列化为JSON时,我得到以下结果(这正是我想要的):
{
"payment" : {
"creditCardPayment": {
...
}
}
不幸的是,如果我使用上面的JSON并尝试将其反序列化回我的对象模型,我会得到以下异常:
无法读取JSON:无法解析类型ID“creditCardPayment” [来源:来自:[简单类型,类别付款]的子类型 org.apache.catalina.connector.CoyoteInputStream@19629355;行:1, 栏:58](通过参考链:订单[“付款”]);嵌套 异常是com.fasterxml.jackson.databind.JsonMappingException: 无法将类型ID“creditCardPayment”解析为子类型 [简单类型,班级付款]在[来源: org.apache.catalina.connector.CoyoteInputStream@19629355;行:1, 专栏: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());
}
}
为了测试,我有一个带有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) {}
}
我已经尝试过关于SO的各种讨论的所有建议,但到目前为止没有运气。谁能发现我做错了什么?
答案 0 :(得分:11)
尝试使用ObjectMapper.registerSubtypes
注册子类型而不是使用注释
答案 1 :(得分: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();
}
注1:我们使用Interface和实现类。我希望jackson根据它们的实现类对类进行反序列化,你必须使用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();
........
}
希望这有帮助!
答案 2 :(得分:3)
我在处理基于dropwizard的服务时遇到了类似的问题。我不完全理解为什么事情对我来说不像dropwizard代码那样有用,但我知道为什么原帖中的代码不起作用。 @JsonSubTypes
想要一个子类型数组,而不是单个值。所以,如果你更换线......
@JsonSubTypes.Type(name = "creditCardPayment", value = CreditCardPayment.class)
...与
@JsonSubTypes({ @JsonSubTypes.Type(name = "creditCardPayment", value = CreditCardPayment.class) })
我相信你的代码会有用。
对于那些弹出相同错误消息的人,您可能遇到了被发现的子类型的问题。尝试添加类似上面的一行,或者通过发现其中包含@JsonTypeName
标记的类来查找问题。
答案 3 :(得分:0)
Rashmin的回答有效,我找到了另一种避免com.fasterxml.jackson.databind.JsonMappingException: Could not resolve type id into a subtype of Blah
问题而无需使用registerSubtypes
的方法。您可以做的是将以下注释添加到父类:
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type")
请注意,差异为JsonTypeInfo.Id.CLASS
而非JsonTypeInfo.Id.NAME
。缺点是创建的JSON将包含整个类名,包括完整的名称空间。好处是你不必担心注册子类型。
答案 4 :(得分:0)
遇到相同的错误并使用下面的JSON(而不是CreditCardPayment
使用我的类名称)作为反序列化器的输入并且它有效:
{
"type": "CreditCardPayment",
...
}
答案 5 :(得分:0)
在我的情况下,我已将defaultImpl = SomeClass.class
添加到@JsonTypeInfo并尝试将其转换为SomeClass2.class