3

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:

  1. 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>
 * &lt;complexType>
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="SomeNumber" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
 *         &lt;element name="ReferenceID" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/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>
 * &lt;complexType name="MyUserResponse">
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="SomeNumber" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
 *         &lt;element name="ReferenceID" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/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>
 * &lt;complexType>
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="MyUserResponse" type="{http://tempuri.org/}MyUserResponse" maxOccurs="unbounded" minOccurs="0"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/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.

user3777801
  • 91
  • 1
  • 3
  • 9

4 Answers4

7

Just a quote from the link i got:

The above exception occurs because JAXB always expects a @XmlRootElement annotation on the entity, it gets to marshal. This is mandatory and can not be skipped. This @XmlRootElement annotation is required to get meta data from root element of XML marshalled from java object. ArrayList class OR any java collection class does not have any JAXB annotations on it. Due to this JAXB is unable to parse any such java objects and raises this error.

[Solved]: javax.xml.bind.JAXBException: class java.util.ArrayList nor any of its super class is known to this context

Seems your MyUserResponse does not have the @XMLRootElement annotaion.

Santosh Joshi
  • 3,290
  • 5
  • 36
  • 49
  • Thanks. But i tried this option early too and today again but no help. I am still getting the same exception. :( – user3777801 Jun 26 '14 at 14:00
  • Any Suggestion please. I am still facing this issue. – user3777801 Jun 29 '14 at 14:14
  • How have u generated your POJO's, Can u regenerate them. – Santosh Joshi Jun 30 '14 at 03:44
  • I generated POJO files using JAXB2Marshaller xjc compiler but exception "JAXBException: class java.util.ArrayList nor any of its super class is known to this context. " comes when I sent list of items from service layer. i generated pojo 2-3 times but no help. If I change my xsd file for receiving one record only and generate Pojo accordingly using xjc compiler and then send only one record from my service layer then Jaxb2marshaller works fine and I receive the result but throw exception when multiple record. – user3777801 Jun 30 '14 at 05:07
4

I have met the same issue, you can check the line of code like this:
jaxbMarshaller.marshal(obj, sw);
- make sure obj is not a collection
- obj is parent class which reflects XML root.
Hope this help!

Mr Special
  • 1,576
  • 1
  • 20
  • 33
3

This worked for me:

javax.xml.bind.JAXBException: Class *** nor any of its super class is known to this context

Just add XmlSeeAlso annotation to your response class:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {"myUserResponse"})
@XmlRootElement(name = "MyUserResponses")
@XmlSeeAlso(ArrayList.class)
public class MyUserResponses {

    @XmlElement(name = "MyUserResponse")
    protected List<MyUserResponse> myUserResponse;
    ...
Community
  • 1
  • 1
mota
  • 193
  • 2
  • 12
  • 1
    Implementing this solution gives me this exception - "unable to marshal type "java.util.ArrayList" as an element because it is missing an @XmlRootElement annotation" – balajiprasadb Dec 28 '16 at 06:16
  • This seems to occur when you return a list of things in your web method. Try returning an object that holds a list of things. – Markus Barthlen Mar 13 '17 at 10:53
1

I have got similar issue, I had generated the stubs using CXF. I got similar error and on analysis I have found that the list I'm creating had some null values which caused it. I have replaced null values with empty string. My code is as below using Java 8. If I enable the commented line of code I get java.util.ArrayList nor any of its super class is known to this context exception.

Hope this will help someone.

    model.keySet().forEach( val ->{
                TestRequest.Param param = new Param();
                param.setKey(val);
                param.setValue(model.get(val) != null ?model.get(val).toString():""); //works fine   
                    //below line has caused the issue
                    //param.setValue(model.get(val));
                request.getParam().add(param);// this is the list on my request
            });
Vins
  • 1,931
  • 16
  • 14