سؤال

Ok, I've searched everywhere for an answer to this. It is driving me nuts.

All I need to do is unmarshal a very simple webservice response. The only problem is, I am using a generated source file without the @XmlRootElement annotation. I am unable to edit this generated source file to add @XmlRootElement, either. I need to use it "as is".

This is the current code that I have, but it is resulting in an error shown at the bottom of this post. I have tried to use a JAXBElement wrapper but to no avail. Could somebody please give me the code I need? I have no idea how to use "QName"s etc.

This code below works great with classes that have @XmlRootElement:

 MyGeneratedClass response = restTemplate.getForObject("url to webservice!"),
     MyGeneratedClass.class);

 return response

Sadly, it is producing this error in this case. Please help me to unmarshal the REST response!

 Could not extract response: no suitable HttpMessageConverter found for response
    type [MyGeneratedClass] and content type [application/xml;version=1]
هل كانت مفيدة؟

المحلول

I forgot about posting this many months ago and I should probably follow it up with the solution. This solution also adds a cookie to the request headers, but you can ignore that. In the case that a generated source file does not have @XmlRootElement annotation, you can unmarshal as follows:

// Cookie setting
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("Cookie", "myCookie=value");
HttpEntity<?> requestEntity = new HttpEntity(requestHeaders);

HttpEntity<String> response = restTemplate.exchange("web service url"), 
    HttpMethod.GET, requestEntity, String.class);

// Unmarshalling
JAXBElement<MyGeneratedClass> result = 
    (JAXBElement<MyGeneratedClass>) unmarshaller.unmarshal(
        new StreamSource(new ByteArrayInputStream(response.getBody().getBytes())));

return result.getValue();

نصائح أخرى

Spring's RestTemplate relies on HttpMessageConverter to unmarshal an object to XML. More specifically the Jaxb2RootElementHttpMessageConverter.canWrite method is responsible for the error you are seeing. Even if you were to override the canWrite method to not care whether the XmlRootElement annotation was present, JAXB would be unable to unmarshal the object.

One way around this limitation is to override Jaxb2RootElementHttpMessageConverter.canWrite to not check for the presence of the XmlRootElement annotation AND use EclipseLink's Moxy JAXB implementation with a mapping file. In the mapping file you can specify the equivalent of the XmlRootElement annotation, allowing you to use JAXB without using annotation's in your Java class.

Spring's RestTemplate is typically used together with org.springframework.oxm.jaxb.Jaxb2Marshaller. Unfortunately, that class has a property supportJaxbElementClass set to false by default :(

Spring nowhere documents this property, and numerous questions about RestTemplate/ JAXBELement on the Spring Forums have been unanswered :((((

Fortunately, you can configure Jaxb2Marshaller setting its property supportJaxbElementClass to true!

The following example configuration of RestTemplate will correctly marshall and unmarshall objects of type JAXBElement

<beans>
  <bean id="httpClient" class="org.apache.http.impl.client.DefaultHttpClient">
    <constructor-arg>
      <bean class="org.apache.http.impl.conn.PoolingClientConnectionManager" />
    </constructor-arg>
  </bean>

  <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
    <constructor-arg>
      <bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
        <constructor-arg ref="httpClient" />
      </bean>
    </constructor-arg>
    <!-- Configure the Rest template to translate between XML and JAXB -->
    <property name="messageConverters">
      <list>
        <bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
          <property name="marshaller" ref="jaxbMarshaller" />
          <property name="unmarshaller" ref="jaxbMarshaller" />
        </bean>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>        
      </list>
    </property>
  </bean>
  <bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="supportJaxbElementClass" value = "true"/>
    <property name="packagesToScan">
      <list>
        <value>com.myorg.path.to.JAXB.classes</value>
      </list>
    </property>
  </bean>
</beans>
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top