[英]Camel CXF endpoint not returning POJO
如何讓 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]
這是處理器可用的實際消息有效負載的內容。
這是我要發送的消息。
如何讓 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>
您不需要 CxfTransport,也不需要指定dataFormat=POJO
因為這已經是默認數據格式。 您的類應該是 JAXB 注釋並在您的服務類 (net.webservicex.GlobalWeatherSoap) 中引用。
這是它的外觀示例:
國家.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 中使用的名稱。
根據 SOAP 消息(標頭、正文、附件)的性質,CXF Endpoint 不會將 JAXB 作為 POJO 解組的<soap:Body>
內容放入 Camel Excahnge 正文中。
但是正如你所看到的,CXF 把一個org.apache.cxf.message.MessageContentsList
它包含在 WSDL 中定義的message
部分。 然后<soap:Body>
實際 POJO 是 MessageContentsList 第一個元素,然后是其他部分 - 標題等。
因此,在您的MessageConverterBean.process
方法中,您必須從 MessageContentsList 中獲取第一個元素以獲取 POJO - 這是您的GetCitiesByCountry
對象。
例如不是
GetCitiesByCountry body = e.getIn().getBody(GetCitiesByCountry.class);
但像
GetCitiesByCountry body = (GetCitiesByCountry)((MessageContentsList)e.getIn().getBody()).get(0);
正如@Vadim 所述,您的處理器必須從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")
Spring 上下文:
<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>
還有你可以實現的方法transform()
,它看起來像這樣:
public class Router extends RouteBuilder {
@Override
public void configure() throws Eception {
from("direct:yourEndpoint")
.to("cxf:bean:WebService")
.transform(simple("${body[0]}"))
.end();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.