Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/397.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在返回多种XML类型的URL上使用SpringRESTTemplate和JAXB编组_Java_Jaxb_Resttemplate - Fatal编程技术网

Java 如何在返回多种XML类型的URL上使用SpringRESTTemplate和JAXB编组

Java 如何在返回多种XML类型的URL上使用SpringRESTTemplate和JAXB编组,java,jaxb,resttemplate,Java,Jaxb,Resttemplate,我需要向返回或且始终返回状态代码200的服务发送Rest POST。(蹩脚的第三方产品!) 我有如下代码: Job job = getRestTemplate().postForObject(url, postData, Job.class); 我的applicationContext.xml如下所示: <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"> <const

我需要向返回
且始终返回状态代码
200
的服务发送Rest POST。(蹩脚的第三方产品!)

我有如下代码:

Job job = getRestTemplate().postForObject(url, postData, Job.class);
我的applicationContext.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>
在postForObject()调用中,我请求一个Job.class,但没有得到它,它很不高兴

我想我需要能够按照以下思路做一些事情:

Object o = getRestTemplate().postForObject(url, postData, Object.class);
if (o instanceof Job.class) {
   ...
else if (o instanceof Exception.class) {
}
但这不起作用,因为JAXB抱怨它不知道如何封送到Object.class——这并不奇怪

我试图创建MarshallingHttpMessageConverter的子类并重写readFromSource()

受保护的对象readFromSource(类clazz、HttpHeaders和Source){

不幸的是,这不起作用,因为在我重试时,源中的底层inputstream已经关闭

感谢您的建议

汤姆

更新:我通过复制inputStream来实现这一点

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;

}

@汤姆:我不认为创建一个定制的MarshallingHttpMessageConverter会对你有任何好处。内置的转换器会返回正确的类(异常类)当服务失败时,
restemplate
不知道如何将异常类返回给被调用方,因为您已将响应类型指定为作业类

我阅读了,您当前正在调用此API:-

public <T> T postForObject(URI url, Object request, Class<T> responseType) throws RestClientException {
    HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(request, responseType);
    HttpMessageConverterExtractor<T> responseExtractor =
            new HttpMessageConverterExtractor<T>(responseType, getMessageConverters());
    return execute(url, HttpMethod.POST, requestCallback, responseExtractor);
}
如果在某些情况下您希望重用来自
restemplate
的一些API,那么您可以构建一个适配器来包装您的自定义实现,并重用
restemplate
API,而无需在整个代码中实际公开
restemplate
API

例如,您可以创建适配器接口,如下所示:-

public interface MyRestTemplateAdapter {
    Object genericPost(String url);

    // same signature from RestTemplate that you want to reuse
    <T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables);
}
public class MyRestTemplateAdapterImpl implements MyRestTemplateAdapter {
    @Autowired
    private RestTemplate    restTemplate;

    @Autowired
    private Jaxb2Marshaller jaxb2Marshaller;

    public Object genericPost(String url) {
        // code from above
    }

    public <T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables) {
        return restTemplate.postForObject(url, request, responseType);
    }
}
公共接口MyRestTemplateAdapter{
对象genericPost(字符串url);
//要重用的RestTemplate中的相同签名
T postForObject(字符串url、对象请求、类响应类型、对象…变量);
}
具体的自定义rest模板如下所示:-

public interface MyRestTemplateAdapter {
    Object genericPost(String url);

    // same signature from RestTemplate that you want to reuse
    <T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables);
}
public class MyRestTemplateAdapterImpl implements MyRestTemplateAdapter {
    @Autowired
    private RestTemplate    restTemplate;

    @Autowired
    private Jaxb2Marshaller jaxb2Marshaller;

    public Object genericPost(String url) {
        // code from above
    }

    public <T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables) {
        return restTemplate.postForObject(url, request, responseType);
    }
}
公共类MyRestTemplateAdapterImpl实现MyRestTemplateAdapter{
@自动连线
私有RestTemplate RestTemplate;
@自动连线
专用Jaxb2Marshaller Jaxb2Marshaller;
公共对象genericPost(字符串url){
//上面的代码
}
公共T postForObject(字符串url、对象请求、类响应类型、对象…变量){
返回restemplate.postForObject(url、请求、响应类型);
}
}

我仍然认为这种方法比子类化
restemplate
要干净得多,您可以更好地控制如何处理来自web服务调用的结果。

在尝试解决相同问题时,我发现了以下解决方案

我使用RestTemplate的默认实例,并使用xjc生成文件

如果输入类使用XmlRootElement注释,那么转换器将返回“real”类型

protected Object readFromSource(Class clazz, HttpHeaders headers, Source source)
如果clazz存在XmlRootElement注释,则可能返回不是clazz实例的对象。在这种情况下,clazz仅用于创建将对clazz进行解组的解组器

下面的技巧解决了这个问题:如果我们定义

@XmlRootElement()
@XmlSeeAlso({ Exception.class, Job.class })
public static abstract class XmlResponse {}
并将XmlResponse.class传递给postForObject(…),则响应将是异常或作业


这有点像黑客,但它解决了postForObject方法无法返回多个对象类的问题。

关于如何处理转换的调用应该在这之前的一层中处理。实现一个自定义MessageConverter如何,该转换器可以处理,根据结果数据调用正确的转换模块。I h实际上我一直在尝试类似的东西,但到目前为止没有乐趣-我将用我尝试过的东西更新问题。我尝试过扩展该类,并根据您的建议添加一个返回“Object”的方法副本,但HttpEntityRequestCallback具有私有访问权限,所以我不太确定如何做。您能提供一个示例吗?@Tom:i updated我在上面的帖子。这是一种不同的方法,但我相信它应该能为您的问题提供一个优雅的解决方案。嗨,limc,谢谢您的建议。我今天就尝试一下。
IOUtil.toString(method.getResponseBodyAsStream());
-此处使用的是隐式平台默认编码。使用
IOUtils
InputStream
复制到
ByteArrayOutputStream
中并使用其
getBytes()会更干净
作为
ByteArrayInputStream
@limc的构造函数参数,我对RestTemplate有一个类似的问题。如果可能的话,你能帮助我吗?@xmlsee也很棒!如果你想在它的子类中使用
@XmlValue
,你还需要将
@xmltransive
添加到XmlResponse类中
protected Object readFromSource(Class clazz, HttpHeaders headers, Source source)
@XmlRootElement()
@XmlSeeAlso({ Exception.class, Job.class })
public static abstract class XmlResponse {}