[英]Jackson ignores xml root element for abstract class
我正在将应用程序从Jersey迁移到Spring MVC,并且在使Jackson与旧版xml兼容时遇到问题。 我在请求正文上收到一个抽象对象,如下所示
MyController.java
@RequestMapping(method = RequestMethod.PUT, value = ConnectorConstants.SUBSCRIBE_KEY)
public Callable<SubscribeResult> subscribe(
@PathVariable final String userKey,
@RequestBody(required = false) final SubscribeRequest subscribeRequest)
{
return new Callable<SubscribeResult>()
{
@Override
public SubscribeResult call() throws Exception
{
return someService.subscribe(userKey, subscribeRequest);
}
};
}
SubscribeRequest.java
@XmlRootElement(name = "subscribe_request")
@XmlSeeAlso({ OneRequest.class, AnotherRequest.class, SimpleDomainRequest.class })
public abstract class SubscribeRequest implements Request {
/* (non-Javadoc)
* @see com.company.client.request.Request#getBody()
*/
@Override
public abstract <K, V> Map<K, V> getBody();
protected final Map<Object, Object> params = new HashMap<Object, Object>();
}
SimpleDomainRequest.java
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "simple_domain_request")
public class SimpleDomainRequest extends SubscribeRequest
{
... methods
}
AnotherRequest.java
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "another_request")
public class AnotherRequest extends SubscribeRequest
{
... methods
}
OneRequest.java
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "one_request")
public class OneRequest extends SubscribeRequest
{
... methods
}
如果对象的类型为SimpleDomainRequest,则这是控制器接收的xml之一:
<simple_domain_request>
<params>
<entry>
<key
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">MY KEY
</key>
<value
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">MY VALUE
</value>
</entry>
</params>
</simple_domain_request>
因此,除了控制器使用的运动衫部分有所不同之外,我的代码都能正常工作,运动衫控制器对对象进行反序列化没有问题。 但是,在迁移使用Spring-MVC和Jackson之后,就无法对其进行反序列化。 从我读到的内容来看,杰克逊不支持@XmlSeeAlso,所以我尝试根据在支持杰克逊抽象类的指南中进行以下更改:
SubscribeRequest
@XmlRootElement(name = "subscribe_request")
@XmlSeeAlso({ OneRequest.class, AnotherRequest.class, SimpleDomainRequest.class })
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonSubTypes({
@JsonSubTypes.Type(value = SimpleDomainRequest.class, name = "simple_domain_request"),
@JsonSubTypes.Type(value = AnotherRequest.class, name = "another_request"),
@JsonSubTypes.Type(value = OneRequest.class, name = "one_request")
})
public abstract class SubscribeRequest implements Request {
/* (non-Javadoc)
* @see com.company.client.request.Request#getBody()
*/
@Override
public abstract <K, V> Map<K, V> getBody();
@JsonProperty
protected final Map<Object, Object> params = new HashMap<Object, Object>();
}
但是我从杰克逊收到以下错误: 无法解析类型id'params'
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Could not resolve type id 'params' into a subtype of [simple type, class com.company.SubscribeRequest]: known type ids = [SubscribeRequest, one_request, simple_domain_request, another_request]
at [Source: java.io.PushbackInputStream@55416df4; line: 4, column: 13]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148) ~[jackson-databind-2.5.1.jar:2.5.1]
at com.fasterxml.jackson.databind.DeserializationContext.unknownTypeException(DeserializationContext.java:948) ~[jackson-databind-2.5.1.jar:2.5.1]
at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._handleUnknownTypeId(TypeDeserializerBase.java:275) ~[jackson-databind-2.5.1.jar:2.5.1]
at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._findDeserializer(TypeDeserializerBase.java:162) ~[jackson-databind-2.5.1.jar:2.5.1]
at com.fasterxml.jackson.databind.jsontype.impl.AsWrapperTypeDeserializer._deserialize(AsWrapperTypeDeserializer.java:100) ~[jackson-databind-2.5.1.jar:2.5.1]
at com.fasterxml.jackson.databind.jsontype.impl.AsWrapperTypeDeserializer.deserializeTypedFromObject(AsWrapperTypeDeserializer.java:49) ~[jackson-databind-2.5.1.jar:2.5.1]
at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserializeWithType(AbstractDeserializer.java:131) ~[jackson-databind-2.5.1.jar:2.5.1]
at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:42) ~[jackson-databind-2.5.1.jar:2.5.1]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3562) ~[jackson-databind-2.5.1.jar:2.5.1]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2662) ~[jackson-databind-2.5.1.jar:2.5.1]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:205) ~[spring-web-4.1.5.RELEASE.jar:4.1.5.RELEASE]
这是我的消息转换器配置:
public class WebConfigurationAdapter extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters)
{
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.featuresToEnable(MapperFeature.DEFAULT_VIEW_INCLUSION);
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
}
如果我将其更改为使用UNWRAP_ROOT_VALUE
builder.featuresToEnable(MapperFeature.DEFAULT_VIEW_INCLUSION, DeserializationFeature.UNWRAP_ROOT_VALUE);
然后我得到这个错误:
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Root name 'params' does not match expected ('SubscribeRequest') for type [simple type, class com.company.SubscribeRequest]
如果我的请求正文包装在某些xml标记中,则它可以工作:
<any_name_here_doesnt_matter>
<simple_domain_request>
<params>
<entry>
<key
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">MY KEY
</key>
<value
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">MY VALUE
</value>
</entry>
</params>
</simple_domain_request>
</any_name_here_doesnt_matter>
请记住,即使以为我有权访问SubscribeRequest类也需要保持兼容性,因此无法更改收到的xml。 DEFAULT_VIEW_INCLUSION在那里,因为我将JsonView用于其他对象。
我可能在这里缺少明显的东西,因此不胜感激,或者如果您需要查看更多我的代码,则为您提供帮助。
Pom.xml声明杰克逊
<properties>
<woodstox-core-asl.version>4.4.1</woodstox-core-asl.version>
<jackson.version>2.5.1</jackson.version>
</properties>
<!-- Jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>
<version>${woodstox-core-asl.version}</version>
</dependency>
春季版本为4.1.5。
使用@JacksonXmlRootElement(localName = "simple_domain_request"
批注,而不是@XmlRootElement(name = "simple_domain_request")
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.