是否可以指定多个预期响应类型?

时间:2014-05-07 14:32:39

标签: java spring spring-integration

TL;博士

我有一个REST服务,它响应XML主体。我想使用HTTP消息转换器解组响应。但是,从服务返回的XML并不总是映射到单个Java类型。如何配置HTTP出站网关以期望多种响应类型?


我正在使用

  • Java 1.6
  • Spring Integration 3.0.0.RELEASE
  • Spring Integration HTTP 3.0.0.RELEASE
  • Spring OXM 4.0.1.RELEASE

我正在尝试设置调用REST服务的int-http:outbound-gateway。 REST服务使用&text; / xml'进行响应。我希望能够使用MarshallingHttpMessageConverter来编组对Java对象的响应。

REST服务可以响应成功的' XML响应或“错误”#39; XML响应。例如,它可能会返回:

<?xml version="1.0" encoding="UTF-8"?>
<success>
    <yay>You're call was successful, here is the information you wanted.</yay>
    <information>very important stuff</information>
</success>

或者它可能会返回:

<?xml version="1.0" encoding="UTF-8"?>
<failure>
    <boo>You're call was unsuccessful, go in the corner and cry.</boo>
    <error>very important error code</error>
</failure>

因此,我需要设置2个Java对象来映射这些不同的响应。所以我创造了

Success.java:

@XmlRootElement(name = "success")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Success{

    private String yay;
    private String information;

    @XmlElement(name = "yay")
    public String getYay() {
        return yay;
    }

    @XmlElement(name = "information")
    public String getInformation() {
        return information;
    }
    //setters omitted for brevity.
}

Failure.java:

@XmlRootElement(name = "failure")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Failure{

    private String boo;
    private String information;

    @XmlElement(name = "boo")
    public String getBoo() {
        return boo;
    }

    @XmlElement(name = "error")
    public String getError() {
        return error;
    }
    //setters omitted for brevity.
}

现在,为了设置出站网关,我RestTemplate配置了MarshallingHttpMessageConverter。在MarshallingHttpMessageConverter上,我注入了一个绑定了Success和Failure对象的OXM unmarshaller:

<oxm:jaxb2-marshaller id="myRestMarshaller">
    <oxm:class-to-be-bound name="com.example.Success" />
    <oxm:class-to-be-bound name="com.example.Failure" />
</oxm:jaxb2-marshaller>

问题在于,当我尝试设置int-http:outbound-gateway时,我只能将com.example.Successcom.example.Failure中的一个放入expected-response-type属性中。如果我选择使用Success,如果REST服务以Failure响应,则会抛出异常,反之亦然。

<int-http:outbound-gateway
    id="myRestServiceGateway"
    url-expression="'http://localhost:8855/webapp/ws/testId/{testId}'"
    http-method="GET" 
    request-channel="restRequest"
    reply-channel="restResponse" 
    rest-template="restTemplate"
    expected-response-type="com.example.Success">

    <int-http:uri-variable name="testId" expression="payload"/>

</int-http:outbound-gateway>

如何告知出站网关响应类型可以是com.example.Success 还是 com.example.Failure

2 个答案:

答案 0 :(得分:2)

Artem Bilan's answer按照要求回答了我的问题。但是,我最终使用另一种方法来实现我的目标。

我设置我的出站网关以接收xml作为字符串,但我没有使用MarshallingHttpMessageConverter。相反,我将出站网关放在一个链中,其中网关是第一个端点,而解组转换器是第二个端点。所以我的配置如下:

<oxm:jaxb2-marshaller id="myRestMarshaller">
    <oxm:class-to-be-bound name="com.example.Success" />
    <oxm:class-to-be-bound name="com.example.Failure" />
</oxm:jaxb2-marshaller>

<int:chain input-channel="restRequest" output-channel="restResponse">
    <int-http:outbound-gateway
        id="myRestServiceGateway"
        url-expression="'http://localhost:8855/webapp/ws/testId/{testId}'"
        http-method="GET" 
        rest-template="restTemplate"
        expected-response-type="java.lang.String">

        <int-http:uri-variable name="testId" expression="payload"/>

    </int-http:outbound-gateway>

    <int-xml:unmarshalling-transformer unmarshaller="myRestMarshaller"/>
</int:chain>

我更喜欢这种方法,因为我认为它提供了更多的关注点分离。现在网关只关心与HTTP服务的通信,而编组人员则关注翻译响应。

我也不需要在我的模型中引入一个永远不会被使用的额外课程。

答案 1 :(得分:1)

  1. 您无法指定多个expected-response-type,因为它是RestTemplate的一部分 通过ResponseExtractor转换回复。

  2. RestTemplate确实使用HttpMessageConverter将响应转换为适当的Java对象。

  3. 由于您希望XML作为响应并希望将其转换为POJO,因此使用MarshallingHttpMessageConverter是正确的方法。

  4. 那么如何处理转换成功和失败响应的要求呢?

    我们无法为RestTemplate配置多种类型,但我们可以为JaxbMarshaller执行此操作。有一种欺骗RestTemplateMarshallingHttpMessageConverter的技巧。

    您可以为SuccessFailure创建超类,并将其配置为expected-response-type。除了class-to-be-boundJaxbMarshaller之外,我还要将Success添加为Failure

    并且不要忘记使用@XmlRootElement标记新的超类,因为JaxbMarshaller默认使用checkForXmlRootElement = true