繁体   English   中英

杰克逊忽略了抽象类的xml根元素

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM