spring – “无法识别的字段(..),未标记为可忽略”而jaxb解组xml输入

在一个典型的
Spring MVC项目中,我试图访问从外部Web服务源获取的对象.这个数据的实际整合实际上并不是 – 直到现在 – 我在项目中的部分.但它已经破了,我将不得不解决它.也就是说:我对相关代码并不完全熟悉.

背景

数据

从外部Web服务接收的XML数据如下所示:

<offeredServiceTOes>
   <OfferedService deleted="false">
      <id>0001_01-u001/igd</id>
      <title>Umschlagleistung (001)</title>
      <mainType>turnover</mainType>
      <services>
         <service id="tos5yyeivg">
            <title>Umschlag Bahn - Binnenschiff</title>
            <mainType>turnover</mainType>
            <systemId>RailRiver</systemId>
            <meansOfTransport id="motRail">
               <title>Bahn</title>
               <description>Bahn</description>
               <systemId>Rail</systemId>
            </meansOfTransport>
            <meansOfTransportRel id="motRiver">
               <title>Binnenschiff</title>
               <description>Binnenschiff</description>
               <systemId>River</systemId>
            </meansOfTransportRel>
         </service>
         <service id="tos5yyeiw0">
            [...]
         </service>
         [...]
      </services>
      [...]
    </OfferedService>
    [...]
<offeredServiceTOes>

解组

>使用Spring Rest模板的方法如下所示:

@Override
public List<OfferedServiceTO> getOfferedServices() {
    return restTemplate.getForObject(
            dataServiceUriTemplate, 
            OfferedServiceTOList.class,
            OFFERED_SERVICES
    );

>相关的OfferedServiceTOList类:

@XmlRootElement(name="OfferedService")
public class OfferedServiceTO
{

    @XmlElement
    @XmlID
    public String id;

    // [...]

    @XmlElementWrapper(name="services")
    @XmlElement(name="service")
    public List<ServiceTO> services; 

    // [...]
}

>相关的ServiceTO类

@XmlRootElement(name="service")
public class ServiceTO
{
    // [...]
    @XmlElement
    public String title;

    /[...]
    @XmlElementWrapper(name="mainServices")
    @XmlElement(name="service")
    public List<ServiceTO> mainServices;
}

> marshaller / unmarshaller xml bean配置

<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="classesToBeBound">
        <list>
            <value>a.b.beans.ServiceTO</value>
            <value>a.b.OfferedServiceTO</value>
            [...]
        </list>
    </property>
</bean>

<bean id="xmlMessageConverter"
    class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
    <constructor-arg ref="jaxbMarshaller" />
</bean>

<bean id="jsonHttpMessageConverter"
    class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
    <property name="objectMapper" ref="jaxbJacksonObjectMapper"/>
</bean>

<bean id="jaxbJacksonObjectMapper"
    class="a.b.path.to.extended.jaxb.JaxbJacksonObjectMapper">
</bean>

<bean id="jsonView" class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
    <property name="objectMapper" ref="jaxbJacksonObjectMapper" />
</bean>

>最后,上面提到的path.to.extended.jaxb.JaxbJacksonObjectMapperis:

    public class JaxbJacksonObjectMapper extends ObjectMapper {

        public JaxbJacksonObjectMapper() {
            final AnnotationIntrospector primary = new JaxbAnnotationIntrospector();
            final AnnotationIntrospector secondary = new JacksonAnnotationIntrospector();
            AnnotationIntrospector introspector = new AnnotationIntrospector.Pair(primary, secondary);
            DeserializationConfig deserializationConfig = super.getDeserializationConfig().withAnnotationIntrospector(introspector);
            DeserializationProblemHandler errorHandler = new DeserializationProblemHandler() {
                @Override
                public boolean handleUnknownProperty(DeserializationContext ctxt, JsonDeserializer<?> deserializer, Object beanOrClass,
                        String propertyName) throws IOException, JsonProcessingException {
                    //TODO Logging (unbekanntes Input-JSON)
                    ctxt.getParser().skipChildren();
                    return true;
                }
            };
            deserializationConfig.addHandler(errorHandler );
            super.setDeserializationConfig(deserializationConfig);
            SerializationConfig serializationConfig = super.getSerializationConfig().withAnnotationIntrospector(introspector);
            serializationConfig.set(Feature.WRAP_ROOT_VALUE, true);
            super.setSerializationConfig(serializationConfig);
        }

    }

问题

问题是,对于xml数据包装,第一个列表的注释@XmlElementWrapper(name =“services”)@XmlElement(name =“service”)对我来说很好.但我一直收到错误:

[...] nested exception is org.springframework.web.client.ResourceAccessException: I/O error: Unrecognized field "service" (Class a.b.ServiceTO), not marked as ignorable
 at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@76d697d9; line: 7, column: 18] (through reference chain: a.b.OfferedServiceTO["services"]->a.b.ServiceTO["service"]); nested exception is org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "service" (Class a.b.ServiceTO), not marked as ignorable
 at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@76d697d9; line: 7, column: 18] (through reference chain: a.b.OfferedServiceTO["services"]->a.b.ServiceTO["service"])
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)

类似的相关问题如this one通过注释@XmlElementWrapper(name =“services”)来修复.但这已经存在了.

我将不胜感激任何建议.谢谢.

– 马丁

最佳答案 好的,这比预期的要容易. List字段需要一个包装层.仔细看看json文档揭示了解决方案:

在OfferedServiceTO.class中

@XmlElementWrapper(name="services")
@XmlElement(name="service")
public List<ServiceTO> services;

必须改为

@XmlElement(name="services")
public ServiceTOList services;

ServiceTOList.class必须是这样的:

@XmlRootElement(name="service")
public class ServiceTOList extends ArrayList<ServiceTO> {

    public List<ServiceTO> services;
}
点赞