I am new with Spring integration and while working for my project requirement. I am facing the below issue to marshall Pojo(java object) to the SOAP response(Using Spring integration ws): Please find the below details for the same:
I have the sample xsd file as below:
</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>
I have created the below java object files using xjc compiler:
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;
}
}
Another Java object:
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 file as below:
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;
}
}
Object Factory:
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 file:
@javax.xml.bind.annotation.XmlSchema(namespace = "http://tempuri.org/", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.myuser.echannel;
I am handling the SOAP request with the request body as below to my spring integration layer(which is the below web.xml and spring context files):
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 file:
<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>
as above, I am using the Jaxb2Marshaller for marshalling and unmarshalling purpose. Now serviceImpl file is as below:
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;
}
}
Here I am calling DB layer and getting List of the MyUserResponse(multiple records) from DB and using spring integration marshaller Jaxb2Marshaller, I am expecting this will marshall the java object into soap response and should display this list in the SOAPUI for MyUserResponse list. but I am getting the below error on SOAP UI and from 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>
error generated from Junit:
org.springframework.ws.soap.client.SoapFaultClientException: 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. at org.springframework.ws.soap.client.core.SoapFaultMessageResolver.resolveFault(SoapFaultMessageResolver.java:37) at org.springframework.ws.client.core.WebServiceTemplate.handleFault(WebServiceTemplate.java:776) at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:602) at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:539) at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:494) at org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceiveToResult(WebServiceTemplate.java:438) at org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceiveToResult(WebServiceTemplate.java:423) at com.nbad.eChannel.Common.InContainerTests.testWebServiceRequestAndResponse(InContainerTests.java:44) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) at org.junit.runners.ParentRunner.run(ParentRunner.java:309) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
My SOAP request is as below:
<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>
Again I receive the proper response(one record) if I do changes in the xsd file for getting the single record and corresponding changes in java object file created but face issue when try to get multiple record response.
Please help me to find where I am doing mistake or missing something.