Page 2 of 2 FirstFirst 12
Results 11 to 13 of 13

Thread: Error: SOAP response is missing outer xml element

  1. #11
    Join Date
    Feb 2006
    Posts
    164

    Default Problem solved by moving to JAXB 2.0

    Hi, everyone.

    I imagine Arjen will try to resolve the problem for this in JAXB 1.0, but I have solved it by moving to JAXB 2.0.

    Basically, you have to:

    (1) Change your request element in invokeInternal(Object requestObject) to cast from JAXBElement, and you have to create a new JAXBElement as the return value. Example (may not be perfect, but should get you close):

    Code:
      protected Object invokeInternal(Object requestObject) throws Exception {
        JAXBElement<TestRqTyp> rqElement = (JAXBElement<TestRqTyp>) requestObject;
        TestRqTyp request = rqElement.getValue();
          TestService ts = new TestService();
          TestRsTyp response = ts.getRs(request);
          QName rsQName = new QName("http://www.mycompany.com","TestRs");
          JAXBElement<TestRsTyp> rsElement = new JAXBElement<TestRsTyp>(rsQName,TestRsTyp.class,response);
          return rsElement;
    Note the difference in the above, when compared to the airline sample, which uses JAXB 1.0.

    (2) Change your ant taskdef for the JAXB code generation from source="1.0" to source="2.0". Example:

    Code:
        <target name="generate-jaxb">
            <taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask" classpathref="compile.classpath"/>
    
            <xjc target="${target.gen.java.dir}" package="${jaxb.package}" source="2.0">
                <schema dir="${src.web.dir}">
                    <include name="**/*.xsd"/>
                </schema>
                <produces dir="${target.gen.java.dir}" includes="**/schema/**/*.java"/>
            </xjc>
        </target>
    (3) Change your jaxbMarshaller in your application context file to use the Jaxb2Marshaller's syntax. Example:

    Code:
       <bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
            <description>
            </description>
            <property name="contextPath" value="com.mycompany.test.schema"/>
            <property name="schema" value="test.xsd"/>        		
        </bean>
    This should probably give someone a good hint as to what the problem is in JAXB 1.0, but I don't see it. Moot point for me, coz I'm shifting to JAXB2. It generates fewer classes and does a few other things better than 1.0.

    Ben

  2. #12
    Join Date
    Jul 2005
    Location
    Rotterdam, the Netherlands
    Posts
    1,562

    Default

    I looked at the sample you provided, and I I've solved your issue (though a bit too late, so it seems ). It has to do with the difference between elements and types in XSD. A type (complex of simple) in an XSD schema is "abstract", meaning that it cannot be used directly, but only referred to in elements or attributes. Though not entirely the same, you can compare a XSD type to an interface in Java, and it's even more like a typedef in C.

    When you generate Java code from the XSD using JAXB, it also generates a class for the type. In the sample you sent me, this was part of the XSD:

    Code:
    <element name="TestRq" type="tns:TestRqTyp" />
    <complexType name="TestRqTyp" mixed="false">
    	<sequence>
    		<element name="TestInput" type="string" minOccurs="0" />
    	</sequence>
    </complexType>
    <element name="TestRs" type="tns:TestRsTyp" />
    <complexType name="TestRsTyp" mixed="false">
    	<sequence>
    		<element name="TestOutput" type="string" />
    	</sequence>
    </complexType>
    This resulted in four generated interfaces: TestRq and TestRs (for the elements), TestRqTyp and TestRsTyp (for the complexTypes). The element interfaces extend the type interfaces, but they are not the same! One is the element, the other is the type.

    Now, the endpoint code contained the following (I've removed some debugging code):

    Code:
      public Object invokeInternal(Object requestObject) throws Exception {
        TestRqTyp request = (TestRqTyp) requestObject;
        TestService ts = new TestService();
        TestRsTyp response = ts.getRs(request);
        return response;
      }
    Note that you're using the type interfaces here, and not the elements. This is ok for the requestObject, because the element extends the type. But this is not OK for the response object, because that results in the type being written, without a wrapping TestRs element:

    Code:
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
      <SOAP-ENV:Header/>
      <SOAP-ENV:Body>
        <TestOutput xmlns="http://www.mycompany.com">BenTestOutputValue</TestOutput>
      </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    To fix this, I changed the above code to:

    Code:
      public Object invokeInternal(Object requestObject) throws Exception {
        TestRq request = (TestRq) requestObject;
        TestService ts = new TestService();
        TestRs response = ts.getRs(request);
        return response;
      }
    which results in the following response message:

    Code:
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
      <SOAP-ENV:Header/>
      <SOAP-ENV:Body>
        <TestRs xmlns="http://www.mycompany.com">
          <TestOutput>BenTestOutputValue</TestOutput>
        </TestRs>
      </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    So, in conclusion, you have to cast the requestObject to a generated element when using JAXB 1.0. When using JAXB 2.0, this is a different matter, because it does not generate classes for elements. So then you have to cast it to a JAXBElement, like you've shown in your post. This is rather unfortunate, because it ties your endpoint code to the marshalling technology you use, while the whole point of the Spring OXM abstractions is to forego this tie-in. I don't know if there is any way to work around this unnecessary tie-in.
    Arjen Poutsma

    Spring Web Services Dev Lead
    Please read the FAQ

  3. #13
    Join Date
    Feb 2006
    Posts
    164

    Default

    Thanks, Arjen. That all makes sense now. Again, feel free to modify/use this as a simple JAXB1 sample (i.e. no Ivy and no database - just simple JAXB), if you wish.

    Ben

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •