Camel CXF端点未返回POJO

时间:2017-11-29 11:14:57

标签: java web-services soap apache-camel cxf

如何让Camel cxfEndpoint返回POJO?目前,它返回MessageContentsList,其中包含SOAP消息字段为String成员。我希望端点返回一个POJO,它是使用cxf-codegen-plugin从wsdl生成的。请注意,为端点提供的服务类是使用相同的工具生成的,并使用这些类。

这是我正在使用的Camel上下文和路由。

<!-- this is a spring XML file where we have Camel embedded -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camel="http://camel.apache.org/schema/spring"
    xmlns:cxf="http://camel.apache.org/schema/cxf"
    xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd">

    <import resource="classpath:META-INF/cxf/cxf.xml"/>
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>

    <bean class="org.apache.camel.component.cxf.transport.CamelTransportFactory" lazy-init="false">
        <property name="bus" ref="cxf"/>
        <property name="camelContext" ref="camelContext"/>
        <property name="checkException" value="true"/>
        <property name="transportIds">
            <list>
                <value>http://cxf.apache.org/transports/camel</value>
            </list>
        </property>
    </bean>

    <bean id="messageLoggerBean" class="tutoivon.api.camel.MessageLoggerBean" />

    <bean id="messageConverterBean" class="tutoivon.api.camel.MessageConverterBean" />

    <cxf:cxfEndpoint id="endpoint" address="http://localhost:1010/hello"
        serviceClass="net.webservicex.GlobalWeatherSoap" wsdlURL="META-INF/globalweather.wsdl">
    </cxf:cxfEndpoint>

    <!-- Here we define Camel, notice the namespace it uses -->
    <camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring">

        <!-- Camel route to move messages from the ActiveMQ inbox to its outbox 
            queue -->
        <route id="cxfToJMSRoute">
            <from uri="cxf:bean:endpoint?dataFormat=POJO" />
            <log message="test" />
            <to uri="bean:messageConverterBean" />
<!--            <convertBodyTo type="String"/> -->
            <wireTap uri="direct:logInfo" />
            <to uri="activemq:queue:api" />
        </route>

        <route id="loggingRoute">
            <from uri="direct:logInfo" />
            <to uri="bean:messageLoggerBean" />
        </route>

    </camelContext>

    <bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
        <property name="brokerURL" value="tcp://127.0.0.1:61616"/>
    </bean>

</beans>

这是处理消息的MessageConverterBean

public class MessageConverterBean implements Processor {

    @Override
    public void process(Exchange e) throws Exception {
        GetCitiesByCountry body = e.getIn().getBody(GetCitiesByCountry.class);

        System.out.println("maa: " + body.getCountryName());

        e.getIn().setBody(body, GetCitiesByCountry.class);
    }

}

但是,无法将正文转换为POJO,因为抛出了以下异常。

org.apache.camel.TypeConversionException: Error during type conversion from type: org.apache.cxf.message.MessageContentsList to the required type: net.webservicex.GetCitiesByCountry with value [Finland] due null
        at org.apache.camel.converter.jaxb.FallbackTypeConverter.convertTo(FallbackTypeConverter.java:166) ~[camel-jaxb-2.20.1.jar!/:2.20.1]
        at org.apache.camel.impl.converter.BaseTypeConverterRegistry.doConvertTo(BaseTypeConverterRegistry.java:366) ~[camel-core-2.20.1.jar!/:2.20.1]
        at org.apache.camel.impl.converter.BaseTypeConverterRegistry.convertTo(BaseTypeConverterRegistry.java:141) ~[camel-core-2.20.1.jar!/:2.20.1]
        at org.apache.camel.impl.MessageSupport.getBody(MessageSupport.java:87) ~[camel-core-2.20.1.jar!/:2.20.1]
        at org.apache.camel.impl.MessageSupport.getBody(MessageSupport.java:61) ~[camel-core-2.20.1.jar!/:2.20.1]
        at tutoivon.api.camel.MessageConverterBean.process(MessageConverterBean.java:12) ~[classes!/:1.0-SNAPSHOT]
        at org.apache.camel.component.bean.AbstractBeanProcessor.process(AbstractBeanProcessor.java:108) ~[camel-core-2.20.1.jar!/:2.20.1]
        at org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:53) ~[camel-core-2.20.1.jar!/:2.20.1]
        at org.apache.camel.component.bean.BeanProducer.process(BeanProducer.java:41) ~[camel-core-2.20.1.jar!/:2.20.1]
        at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:148) ~[camel-core-2.20.1.jar!/:2.20.1]
        at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:548) ~[camel-core-2.20.1.jar!/:2.20.1]
        at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201) [camel-core-2.20.1.jar!/:2.20.1]
        at org.apache.camel.processor.Pipeline.process(Pipeline.java:138) [camel-core-2.20.1.jar!/:2.20.1]
        at org.apache.camel.processor.Pipeline.process(Pipeline.java:101) [camel-core-2.20.1.jar!/:2.20.1]
        at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201) [camel-core-2.20.1.jar!/:2.20.1]
        at org.apache.camel.component.cxf.CxfConsumer$CxfConsumerInvoker.asyncInvoke(CxfConsumer.java:203) [camel-cxf-2.20.1.jar!/:2.20.1]
        at org.apache.camel.component.cxf.CxfConsumer$CxfConsumerInvoker.invoke(CxfConsumer.java:180) [camel-cxf-2.20.1.jar!/:2.20.1]

以下是处理器可用的实际消息有效负载的内容。

enter image description here

这是我发送的消息。

enter image description here

如何让Camel将邮件转换为POJO?以下是我的所有依赖项。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-core</artifactId>
        <version>3.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxws</artifactId>
        <version>3.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http</artifactId>
        <version>3.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http-jetty</artifactId>
        <version>3.2.1</version>
        <exclusions>
            <exclusion>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-continuation</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-http</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-io</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-security</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-server</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-util</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-continuation</artifactId>
        <version>9.4.6.v20170531</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-http</artifactId>
        <version>9.4.6.v20170531</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-io</artifactId>
        <version>9.4.6.v20170531</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-security</artifactId>
        <version>9.4.6.v20170531</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-server</artifactId>
        <version>9.4.6.v20170531</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-util</artifactId>
        <version>9.4.6.v20170531</version>
    </dependency>

    <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-core</artifactId>
        <version>2.20.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-cxf</artifactId>
        <version>2.20.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-jaxb</artifactId>
        <version>2.20.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-cxf-transport</artifactId>
        <version>2.20.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-camel</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-spring</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-broker</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-kahadb-store</artifactId>
    </dependency>
</dependencies>

3 个答案:

答案 0 :(得分:2)

您不需要CxfTransport,也不需要指定dataFormat=POJO,因为这已经是默认数据格式。您的类应该在您的服务类(net.webservicex.GlobalWeatherSoap)中进行JAXB注释和引用。

以下是它的外观示例:

Country.java:

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

@XmlType(name = "GetCitiesByCountry")
@XmlAccessorType(XmlAccessType.FIELD)
public class GetCitiesByCountry {
    String CountryName;
}

GlobalWeatherSoap.java:

import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.jwx.WebResult;

@WebService (targetNamespace="myNamespace")
public interface GlobalWeatherSoap {
    @WebMethod
    @WebResult(name = "GetCitiesByCountryResponse", targetNamespace = "myNamespace")
    public GetCitiesByCountryResponse GetCitiesByCountry(
        @WebParam(name = "GetCitiesByCountry", targetNamespace = "myNamespace")
        GetCitiesByCountry country
    )
}

显然,您将“myNamespace”替换为WSDL中使用的那个。

答案 1 :(得分:0)

如@Vadim所述,您的处理者必须extract来自org.apache.cxf.message.MessageContentsList的回复:

  

camel-cxf端点消费者POJO数据格式基于cxf invoker,因此消息头具有名称为CxfConstants.OPERATION_NAME的属性,消息正文是SEI方法参数的列表

一个简单的测试,用于举例说明SOAP服务的生产者和使用者:

@Test
public void test() {
    final Exchange sender = new DefaultExchange(context, ExchangePattern.InOut);

    final List<Object> messageList = new ArrayList<Object>();
    messageList.add(10);
    messageList.add(10);

    sender.getIn().setHeader(CxfConstants.OPERATION_NAME, "Add");
    sender.getIn().setBody(messageList);

    final Exchange response = template.send("direct:start", sender);

    assertNotNull(response);
    assertThat(response.getIn().getBody(), is(instanceOf(MessageContentsList.class)));
    assertThat((Integer)response.getIn().getBody(MessageContentsList.class).get(0), is(20));
}

根据此要求:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>
    <tem:Add>
        <tem:intA>10</tem:intA>
        <tem:intB>10</tem:intB>
    </tem:Add>
</soapenv:Body>
</soapenv:Envelope>

这个回应:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
    <AddResponse xmlns="http://tempuri.org/">
        <AddResult>20</AddResult>
    </AddResponse>
</soap:Body>
</soap:Envelope>

路线:

 from("direct:start")
     .to("cxf:bean:calculatorEndpoint")

春天背景:

<cxf:cxfEndpoint id="calculatorEndpoint"
    address="http://www.dneonline.com/calculator.asmx" serviceClass="org.tempuri.calculator.CalculatorSoap"
    endpointName="calculator:CalculatorSoap" serviceName="calculator:Calculator"
    wsdlURL="wsdl/org.tempuri.calculator.wsdl" xmlns:calculator="http://tempuri.org/">
</cxf:cxfEndpoint>

答案 2 :(得分:0)

还有方法transform(),您可以实现它,如下所示:

public class Router extends RouteBuilder {

     @Override
     public void configure() throws Eception {

     from("direct:yourEndpoint")
        .to("cxf:bean:WebService")
        .transform(simple("${body[0]}"))
        .end();
     }
}