找不到针对请求类型JAXBElement的合适的HttpMessageConverter

时间:2017-03-13 10:22:56

标签: xml spring jaxb spring-integration spring-rest

我将一个JAXB对象发布到REST服务。生成的类没有XMLRootElement,因此我使用Object Factory createXMl方法创建它。当我手动添加XMLRootElement时,它可以工作,但这只是一种解决方法,因为JAXB类总是在没有XMLRootElement的情况下生成。在发布请求时编组的XMl似乎存在一些问题。

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_XML);
    String userAndPass = "Test:Test123";
    headers.add("Authorization", "Basic " + Base64Utility.encode(userAndPass.getBytes()));

    JAXBElement<DocumentDef> documentDef = PrintFactory.createPrintObjects();

    HttpEntity<JAXBElement<DocumentDef>> request = new HttpEntity<>(documentDef, headers);

    MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
    map.add("lang", "2");

    ResponseEntity<String> result = restTemplate.exchange(url, HttpMethod.POST, request, String.class, map);

PrintFactory.java

      public JAXBElement<DocumentDef> createPrintObjects() {

       DocumentDef documentDef = new DocumentDef();
       JAXBElement<DocumentDef> documentDefJAXBElement = factory.createXml(documentDef);
       return documentDefJAXBElement;
       }

ObjectFactory.java

        /**
 * Create an instance of {@link JAXBElement }{@code <}{@link DocumentDef }{@code >}}
 * 
 */
@XmlElementDecl(namespace = "http://www.example.com/testservice", name = "xml")
public JAXBElement<DocumentDef> createXml(DocumentDef value) {
    return new JAXBElement<DocumentDef>(_Xml_QNAME, DocumentDef.class, null, value);
}

错误:

org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [javax.xml.bind.JAXBElement] and content type [application/xml]
at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:859)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:617)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:588)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:507)

以下HttpMessageConverters已经注册:

org.springframework.http.converter.ByteArrayHttpMessageConverter@68022358, org.springframework.http.converter.StringHttpMessageConverter@7b3a8b9f, org.springframework.http.converter.StringHttpMessageConverter@645e9bc0, org.springframework.http.converter.ResourceHttpMessageConverter@7f438dba, org.springframework.http.converter.xml.SourceHttpMessageConverter@2c0def9c, org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter@46ee015c, org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@2c833e50, org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@339b6365, org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter@1e9a965b

4 个答案:

答案 0 :(得分:0)

嗯,因为以下原因,它不适合你,

JAXBElement<DocumentDef> documentDef = PrintFactory.createPrintObjects();
HttpEntity<JAXBElement<DocumentDef>> request = new HttpEntity<>(documentDef, headers);

同时Jaxb2RootElementHttpMessageConverter就是这样:

* <p>This converter can read classes annotated with {@link XmlRootElement} and
* {@link XmlType}, and write classes annotated with {@link XmlRootElement},
* or subclasses thereof.

public boolean canWrite(Class<?> clazz, MediaType mediaType) {
    return (AnnotationUtils.findAnnotation(clazz, XmlRootElement.class) != null && canWrite(mediaType));
}

当您的JAXBElement完全没有@XmlRootElement时。

尝试找出没有JAXBElement包装器的解决方案。

答案 1 :(得分:0)

我已经通过创建.xjb文件解决了这个问题,该文件自动将XMLRootElement注释附加到父java类,同时生成如下:

<?xml version="1.0" encoding="UTF-8"?>
<jxb:bindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
          xmlns:xs="http://www.w3.org/2001/XMLSchema"
          jxb:extensionBindingPrefixes="xjc" version="1.0">
<jxb:bindings schemaLocation="mySchema.xsd" node="/xs:schema">
    <jxb:globalBindings>
        <xjc:simple/>
    </jxb:globalBindings>
</jxb:bindings>

答案 2 :(得分:0)

如果您需要使用XMLRootElement发布一个没有{}注释的jaxb对象,则解决方案是使用自定义RestTemplate

HttpMessageConverter

请注意,此转换器将尝试转换包装为// jaxb context specific to your xml elements JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class.getPackage().getName()); // custom converter (see declaration below) JaxbElementHttpMessageConverter converter = new JaxbElementHttpMessageConverter(); converter.setJaxbContext(jaxbContext); RestTemplate template = new RestTemplate(); template.getMessageConverters().add(converter); // <--- here // your object needs to be wrapped around a JAXBElement YourRequestObject yourObject = ...; JAXBElement<YourRequestObject> element = new ObjectFactory().createYourRequestObject(request); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_XML); ResponseEntity<YourResponseObject> response = template.postForEntity("/your/url", HttpEntity<>(element, headers), YourResponseObject.class, params); 的所有对象,因此您需要:

  1. 确保您通过其指定的任何元素都可以被您指定的jaxb上下文编组/取消编组;
  2. 将其添加到消息转换器列表的末尾,以便首先尝试更具体的消息转换器。

JAXBElement的定义如下:

JaxbElementHttpMessageConverter

答案 3 :(得分:0)

该问题与 canWrite 类中的 canReadMarshallingHttpMessageConverter 方法有关。这些方法检查编组器和解组器是否支持一个类。就我而言,启用 jaxb 元素支持有所帮助。


MarshallingHttpMessageConverter converter = new   MarshallingHttpMessageConverter();
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setSupportJaxbElementClass(true);
marshaller.setContextPath(ObjectFactory.class.getPackage().getName());
converter.setMarshaller(marshaller);

RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(converter);