【发布时间】:2014-08-16 21:26:25
【问题描述】:
我是 Spring 集成的新手,并且正在为我的项目需求工作。我面临以下问题将 Pojo(java 对象)编组到 SOAP 响应(使用 Spring 集成 ws):请查找以下详细信息:
-
我有如下示例 xsd 文件:
</xsd:element> <xsd:element name="MyUserResponses"> <xsd:complexType> <xsd:sequence> <xsd:element minOccurs="0" maxOccurs="unbounded" name="MyUserResponse" type="tns:MyUserResponse" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:complexType name="MyUserResponse"> <xsd:sequence> <xsd:element minOccurs="0" maxOccurs="1" name="SomeNumber" type="xsd:string"/> <xsd:element minOccurs="0" maxOccurs="1" name="ReferenceID" type="xsd:string" /> </xsd:sequence> </xsd:complexType> </xsd:schema>
我使用 xjc 编译器创建了以下 java 目标文件:
package com.myuser.echannel;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="SomeNumber" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="ReferenceID" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"someNumber",
"referenceID"
})
@XmlRootElement(name = "MyUserRequest")
public class MyUserRequest {
@XmlElement(name = "SomeNumber")
protected String someNumber;
@XmlElement(name = "ReferenceID")
protected String referenceID;
/**
* Gets the value of the someNumber property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getSomeNumber() {
return someNumber;
}
/**
* Sets the value of the someNumber property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setSomeNumber(String value) {
this.someNumber = value;
}
/**
* Gets the value of the referenceID property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getReferenceID() {
return referenceID;
}
/**
* Sets the value of the referenceID property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setReferenceID(String value) {
this.referenceID = value;
}
}
另一个 Java 对象:
package com.myuser.echannel;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for MyUserResponse complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="MyUserResponse">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="SomeNumber" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="ReferenceID" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "MyUserResponse", propOrder = {
"someNumber",
"referenceID"
})
public class MyUserResponse {
@XmlElement(name = "SomeNumber")
protected String someNumber;
@XmlElement(name = "ReferenceID")
protected String referenceID;
/**
* Gets the value of the someNumber property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getSomeNumber() {
return someNumber;
}
/**
* Sets the value of the someNumber property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setSomeNumber(String value) {
this.someNumber = value;
}
/**
* Gets the value of the referenceID property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getReferenceID() {
return referenceID;
}
/**
* Sets the value of the referenceID property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setReferenceID(String value) {
this.referenceID = value;
}
}
MyUserResponses.java 文件如下:
package com.myuser.echannel;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="MyUserResponse" type="{http://tempuri.org/}MyUserResponse" maxOccurs="unbounded" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"myUserResponse"
})
@XmlRootElement(name = "MyUserResponses")
public class MyUserResponses {
@XmlElement(name = "MyUserResponse")
protected List<MyUserResponse> myUserResponse;
/**
* Gets the value of the myUserResponse property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the myUserResponse property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getMyUserResponse().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link MyUserResponse }
*
*
*/
public List<MyUserResponse> getMyUserResponse() {
if (myUserResponse == null) {
myUserResponse = new ArrayList<MyUserResponse>();
}
return this.myUserResponse;
}
}
对象工厂:
package com.myuser.echannel;
import javax.xml.bind.annotation.XmlRegistry;
/**
* This object contains factory methods for each
* Java content interface and Java element interface
* generated in the com.myuser.echannel package.
* <p>An ObjectFactory allows you to programatically
* construct new instances of the Java representation
* for XML content. The Java representation of XML
* content can consist of schema derived interfaces
* and classes representing the binding of schema
* type definitions, element declarations and model
* groups. Factory methods for each of these are
* provided in this class.
*
*/
@XmlRegistry
public class ObjectFactory {
/**
* Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.myuser.echannel
*
*/
public ObjectFactory() {
}
/**
* Create an instance of {@link MyUserResponses }
*
*/
public MyUserResponses createMyUserResponses() {
return new MyUserResponses();
}
/**
* Create an instance of {@link MyUserResponse }
*
*/
public MyUserResponse createMyUserResponse() {
return new MyUserResponse();
}
/**
* Create an instance of {@link MyUserRequest }
*
*/
public MyUserRequest createMyUserRequest() {
return new MyUserRequest();
}
}
package-info.java 文件:
@javax.xml.bind.annotation.XmlSchema(namespace = "http://tempuri.org/", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.myuser.echannel;
我正在处理带有请求正文的 SOAP 请求,如下所示到我的 spring 集成层(即下面的 web.xml 和 spring 上下文文件):
web.xml:
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring-ws-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
spring-ws-config.xml 文件:
<context:component-scan base-package="com.nbad.eChannel"/>
<import resource="classpath:/WEB-INF/inbound-gateway-config.xml"/>
<!-- Ensures that all incoming requests will be routed to the ws:inbound-gateway -->
<!-- <bean class="org.springframework.ws.server.endpoint.mapping.UriEndpointMapping">
<property name="defaultEndpoint" ref="ws-inbound-gateway"/>
</bean> -->
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<property name="mappings">
<props>
<prop key="{http://tempuri.org/}MyUserRequest">ws-myuser-gateway</prop>
</props>
</property>
</bean>
</beans>
<context:component-scan base-package="com.mypackage"/>
<import resource="classpath:/com/mypackage/si/jdbc/config/spring-integration-context.xml"/>
<int:channel id="FFUserRequestChannel"/>
<int-ws:inbound-gateway id="ws-ffuser-gateway" request-channel="FFUserRequestChannel" marshaller="marshaller" unmarshaller="marshaller"/>
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPath" value="com.mypackage.model" />
</bean>
<int:service-activator input-channel="MyUserRequestChannel">
<bean class="com.mypackage.serviceImpl.MyUserImpl">
<constructor-arg ref = "MyUserRequest"></constructor-arg>
</bean>
</int:service-activator>
<bean id="MyUserRequest" class="com.mypackage.model.MyUserRequest"></bean>
<bean id="MyUserResponse" class="com.mypackage.model.MyUserResponse"></bean>
</beans>
如上所述,我使用 Jaxb2Marshaller 进行编组和解组。现在 serviceImpl 文件如下:
package com.mypackage.serviceImpl;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import com.mypackage.model.*;
import com.mypackage.service.MyUser;
import com.mypackage.si.jdbc.service.MyUserJdbc;
/**
* @author Vinay Agrawal
*/
public class MyUserImpl implements MyUser{
@Autowired
MyUserRequest request;
@Autowired
MyUserJdbc MyUserJdbc;
public MyUserImpl() {
}
public MyUserImpl(MyUserRequest request) {
super();
this.request = request;
}
@Override
@PayloadRoot(localPart = "issueResponseFor" , namespace = "http://tempuri.org/")
@ResponsePayload
public List<MyUserResponse>issueResponseFor(@RequestPayload MyUserRequest request) {
List<MyUserResponse> MyUserResponse = new ArrayList<MyUserResponse>();
MyUserResponse = (List<MyUserResponse>)MyUserJdbc.getMyUserResponse(request);
return MyUserResponse;
}
}
在这里,我正在调用 DB 层并从 DB 获取 MyUserResponse(多条记录)的列表,并使用 spring 集成编组器 Jaxb2Marshaller,我希望这会将 java 对象编组为soap响应,并且应该在 MyUserResponse 的 SOAPUI 中显示此列表列表。但我在 SOAP UI 和 Junit 上收到以下错误:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring xml:lang="en">Unknown JAXB exception; nested exception is javax.xml.bind.JAXBException: class java.util.ArrayList nor any of its super class is known to this context.</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
从 Junit 生成的错误:
org.springframework.ws.soap.client.SoapFaultClientException:未知的 JAXB 异常;嵌套异常是 javax.xml.bind.JAXBException: class java.util.ArrayList 或其任何超类在此上下文中都不知道。 在 org.springframework.ws.soap.client.core.SoapFaultMessageResolver.resolveFault(SoapFaultMessageResolver.java:37) 在 org.springframework.ws.client.core.WebServiceTemplate.handleFault(WebServiceTemplate.java:776) 在 org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:602) 在 org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:539) 在 org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:494) 在 org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceiveToResult(WebServiceTemplate.java:438) 在 org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceiveToResult(WebServiceTemplate.java:423) 在 com.nbad.eChannel.Common.InContainerTests.testWebServiceRequestAndResponse(InContainerTests.java:44) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:606) 在 org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) 在 org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 在 org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) 在 org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 在 org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) 在 org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 在 org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 在 org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 在 org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 在 org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 在 org.junit.runners.ParentRunner.run(ParentRunner.java:309) 在 org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 在 org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
我的 SOAP 请求如下:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>
<sch:MyUserRequest>
<sch:SomeNumber>8009618916</sch:SomeNumber>
<sch:ReferenceID>ReferenceIDReferenceID</sch:ReferenceID>
</sch:MyUserRequest>
</soapenv:Body>
</soapenv:Envelope>
如果我在 xsd 文件中进行更改以获取单个记录并在创建的 java 对象文件中进行相应更改,但在尝试获取多个记录响应时遇到问题,我再次收到正确的响应(一条记录)。
请帮我找出我在哪里做错或遗漏了什么。
【问题讨论】:
标签: spring