如何在返回多种类型的 XML 的 URL 上使用 Spring RestTemplate 和 JAXB 编组
我需要对返回 a 或 a 且始终状态代码的服务进行 Rest POST。(蹩脚的第三方产品!<job/>
<exception/>
200
我有这样的代码:
Job job = getRestTemplate().postForObject(url, postData, Job.class);
我的应用程序Context.xml看起来像这样:
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<constructor-arg ref="httpClientFactory"/>
<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.FormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
</list>
</property>
</bean>
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>domain.fullspec.Job</value>
<value>domain.fullspec.Exception</value>
</list>
</property>
</bean>
当我尝试进行此调用并且服务失败时,我得到:
Failed to convert value of type 'domain.fullspec.Exception' to required type 'domain.fullspec.Job'
在postForObject()电话中,我要求一份工作.class没有得到一份工作,它越来越难过。
我想我需要能够做一些事情:
Object o = getRestTemplate().postForObject(url, postData, Object.class);
if (o instanceof Job.class) {
...
else if (o instanceof Exception.class) {
}
但这不起作用,因为JAXB抱怨它不知道如何封送到Object.class - 这并不奇怪。
我试图创建编组HttpMessageConverter的子类并覆盖readFromSource()
protected Object readFromSource(Class clazz, HttpHeaders headers, Source source) {
Object o = null;
try {
o = super.readFromSource(clazz, headers, source);
} catch (Exception e) {
try {
o = super.readFromSource(MyCustomException.class, headers, source);
} catch (IOException e1) {
log.info("Failed readFromSource "+e);
}
}
return o;
}
不幸的是,这不起作用,因为在我重试时,源中的基础输入流已关闭。
任何建议都非常感谢收到,
汤姆
更新:我通过获取输入流的副本来使其工作
protected Object readFromSource(Class<?> clazz, HttpHeaders headers, Source source) {
InputStream is = ((StreamSource) source).getInputStream();
// Take a copy of the input stream so we can use it for initial JAXB conversion
// and if that fails, we can try to convert to Exception
CopyInputStream copyInputStream = new CopyInputStream(is);
// input stream in source is empty now, so reset using copy
((StreamSource) source).setInputStream(copyInputStream.getCopy());
Object o = null;
try {
o = super.readFromSource(clazz, headers, source);
// we have failed to unmarshal to 'clazz' - assume it is <exception> and unmarshal to MyCustomException
} catch (Exception e) {
try {
// reset input stream using copy
((StreamSource) source).setInputStream(copyInputStream.getCopy());
o = super.readFromSource(MyCustomException.class, headers, source);
} catch (IOException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
return o;
}
CopyInputStream取自 http://www.velocityreviews.com/forums/t143479-how-to-make-a-copy-of-inputstream-object.html,我会把它粘贴在这里。
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class CopyInputStream
{
private InputStream _is;
private ByteArrayOutputStream _copy = new ByteArrayOutputStream();
/**
*
*/
public CopyInputStream(InputStream is)
{
_is = is;
try
{
copy();
}
catch(IOException ex)
{
// do nothing
}
}
private int copy() throws IOException
{
int read = 0;
int chunk = 0;
byte[] data = new byte[256];
while(-1 != (chunk = _is.read(data)))
{
read += data.length;
_copy.write(data, 0, chunk);
}
return read;
}
public InputStream getCopy()
{
return (InputStream)new ByteArrayInputStream(_copy.toByteArray());
}
}