Spring RestTemplate cannot unmarshal XML containing “<!DOCTYPE … dtd>”

廉价感情. 提交于 2019-12-11 17:30:04

问题


I call an old web service provided by a third party. I am using Spring RestTemplate:

HttpEntity<MyRequest> requestHttpEntity = new HttpEntity<>(requestBody, headers);
MyResponse response = restTemplate.postForEntity(url, requestHttpEntity, MyResponse.class);

I receive an XML (which format I cannot influence, it's a third party service) as a response:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE MyResponse SYSTEM "http://example.com:8080/some/path/MyResponse.dtd">

<MyResponse>
    ...
</MyResponse>

The postForEntity() method throws the exception

org.springframework.web.client.RestClientException: 
    Error while extracting response for type [class com.example.MyResponse] and content type [text/xml;charset=ISO-8859-1];
nested exception is org.springframework.http.converter.HttpMessageNotReadableException: 
    Could not unmarshal to [class com.example.MyResponse]: null;
nested exception is javax.xml.bind.UnmarshalException

- with linked exception:
     [org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 10;
     DOCTYPE is disallowed when the feature
     "http://apache.org/xml/features/disallow-doctype-decl" set to true.]

I found the only sensible reference to the http://apache.org/xml/features/disallow-doctype-decl feature here: https://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl

Question: How can I customize the unmarshaling without completely avoiding the automagic behavior of Spring RestTemplate? I want to force the unmarshaler to accept XML containing element with DTD reference.

This question is strongly related to my other question How to customize automatic marshaling in Spring RestTemplate to produce/modify XML headers (encoding, DOCTYPE), but the solution proposed there is not easily applicable here.


回答1:


By default the Jaxb2RootElementHttpMessageConverter disables the DTD support (and with that XML Entity support). The reason for this is that it has security implications, see SPR-11376.

To enable it on the Jaxb2RootElementHttpMessageConverter you can set the supportDtd property to true to enable it again. But be aware this will also open up some potential security issues!.

@Bean
public Jaxb2RootElementHttpMessageConverter jaxb2RootElementHttpMessageConverter() {
    Jaxb2RootElementHttpMessageConverter converter = new Jaxb2RootElementHttpMessageConverter();
    converter.setSupportDtd(true);
    return converter;
}

This should be enough to (re)configure support without needing to add any additional configuration. One thing to remember is that this will configure the globally available Jaxb2RootElementHttpMessageConverter and as such will impact all controllers and RestTemplates you might want to use.

Instead of doing this you could also use the RestTemplateBuilder which you should use when creating an instance of the RestTemplate to only influence that specific RestTemplate.

@Bean
public RestTemplate yourRestTemplate(RestTemplateBuilder builder) {
    Jaxb2RootElementHttpMessageConverter converter = new Jaxb2RootElementHttpMessageConverter();
    converter.setSupportDtd(true);

    return builder.messageConverters(converter).build()
}

This way you can configure it specific for that instance of the RestTemplate and configure what you like.



来源:https://stackoverflow.com/questions/47854054/spring-resttemplate-cannot-unmarshal-xml-containing-doctype-dtd

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!