Announcement Announcement Module
Collapse
No announcement yet.
Error: SOAP response is missing outer xml element Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Error: SOAP response is missing outer xml element

    Hi, everyone.

    Hopefully I'm just missing something simple on this:

    Using the SOAPMessage.writeto method (thanks for the tip elsewhere on that one), I see that my response is missing the outermost element in the payload (i.e. my outermost application-functionality element, not any of the SOAP elements):

    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><TxInfo xmlns="http://www.myapp.com"><StatCd>N</StatCd>...

    This SHOULD have contained the outer wrapper element, like this:

    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><GetCitationLstRs xmlns="http://www.myapp.com"><TxInfo><StatCd>N</StatCd>...

    I've used the airline sample as a pattern for a web service, and it (the airline sample) correctly returns the outer wrappering xml element.

    I use JAXB and extend my endpoint class from AbstractMarshallingPayloadEndpoint, same as the airline sample. When I break inside AbstractMarshallingPayloadEndpoint, the requestObject and the responseObject both look reasonable, i.e. contain the outer wrapping element, so I'm thinking the problem is in the marshaller itself...or maybe there is some subtlety to the WSLD or xsd syntax.

    I say "subtlety" coz my WSDL and .xsd validate in Eclipse and I've looked them over carefully. They look reasonable to me.

    Tomcat log shows no errors.

    Has anyone else encountered this problem? Thoughts on where I might look next?

  • #2
    I take it that the PayloadLoggingInterceptor also only shows <TxInfo xmlns="http://www.myapp.com"><StatCd>N</StatCd>... without the wrapping <GetCitationLstRs xmlns="http://www.myapp.com"> element as well?

    It would be interesting to see what kind of XML the unwrapped marshaller generates itself. Could you write a little test code for that, somethis like:

    Code:
    import javax.xml.bind.*;
    public class Sample {
    public static void main(String[] args) throws Exception {
      Object responseObject = createResponseObject();
      JAXBContext jc = JAXBContext.newInstance( "com.acme.foo" );
      Marshaller m = jc.createMarshaller();
      m.marshal( fooObj, System.out );
    }
    }

    Comment


    • #3
      Hi, Arjen.

      I'm not finding a call to PayloadLoggingInterceptor anywhere in the airline sample. Also, when I debug through the Spring code, I'm not seeing it called anywhere in the call stack. Is this a class I'm supposed to add to my app somewhere? or ?

      Ben

      Comment


      • #4
        This may be similar to a problem I was having. Take a look here:
        http://forum.springframework.org/showthread.php?t=26218
        Shannon Kendrick

        Comment


        • #5
          Originally posted by poutsma
          It would be interesting to see what kind of XML the unwrapped marshaller generates itself.
          Arjen, I think maybe there are some obvious errors in your sample above, but no biggie as I think I understood where you were going with it. Implementing your sample in the Endpoint class (i.e. the server side) shows this in the tomcat log:

          <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
          <TxInfo xmlns="http://www.uptodate.com"><StatCd>N</StatCd><InfoMsgs/><WarningMsg
          s/><ErrorMsgs/></TxInfo>

          ...which makes sense, i.e. it looks like a marshalling problem.

          Note that I'm using the JAXB Marshaller for this sample test, not any of the Spring Marshallers.

          Shannon, thanks for the tip. I'll check in out.

          Ben

          Comment


          • #6
            Originally posted by mskendrick
            This may be similar to a problem I was having. Take a look here:
            http://forum.springframework.org/showthread.php?t=26218
            Shannon Kendrick
            I looked this over and I'm not using a binding file (i.e. letting JAXB take all defaults). Also, I'm using JAXB 2.0.1 (I think) since I'm using the same Ivy "repository" and config as the Spring airline sample.

            Ben

            Comment


            • #7
              Originally posted by benethridge
              Arjen, I think maybe there are some obvious errors in your sample above, but no biggie as I think I understood where you were going with it.
              I'm sorry for that, though I can find the error myself . Most of my snippets are sample code, and don't necessarily compile, but I guess it helped you enough.

              Originally posted by benethridge
              ...which makes sense, i.e. it looks like a marshalling problem.
              If it's a marshalling problem, you probably have to tweak the JAXB2 annotations somewhat. You can write some unit tests which validate the XML. XMLUnit really helps you with this (I use it a lot in the SWS test code, especially assertXmlEquals() ).

              Comment


              • #8
                Hi, Arjen.

                I wrote a simple test app in Eclipse that exhibits the problem. I imagine I'm missing something simple, but I just can't see it yet.

                Like the Airline project, but unlike the Echo project, this project uses JAXB. Also the project does NOT use Ivy or multiple build files, so it is quite simple. I can send it to you, but it's 42meg zipped, so I don't think I can post it, can I?

                Arjen, in hindsight, i.e. having gotten the airline sample running ok, the Ivy and the multiple build files might make things easy on you Spring core developers, but they make it hard on us new to Spring, coz we have to go through multiple learning curves at once, making it very hard to figure out if the problem is in our code, the Spring code, the Ivy code, the JAXB code, the Ant code, the Sun code, the Eclipse, and on and on. Each of these comes with its own learning curve and "issues" (quirks and gotcha's).

                Since I really like the Spring Web Service model, and I want it to succeed, and be well-accepted quickly by the java community, it might make that acceptance go faster if the Spring team could remove some of the "variables" in the sample apps. On this I speak with some authority, having been a very successful flight instructor for many years. (Lots of fun but VERY little money in that profession. ). As a teacher, one often has to break down the complex into simple learnable units, not for the benefit of the teacher, but for the benefit of the student...which ultimately "benefits" the teacher as well, now that I think of it.

                If you think this is a good, simple example of JAXB usage in Spring WS, you have my permission to use it and modify it in any way you choose.

                Ben

                Comment


                • #9
                  Originally posted by benethridge
                  I wrote a simple test app in Eclipse that exhibits the problem. I imagine I'm missing something simple, but I just can't see it yet.

                  Like the Airline project, but unlike the Echo project, this project uses JAXB. Also the project does NOT use Ivy or multiple build files, so it is quite simple. I can send it to you, but it's 42meg zipped, so I don't think I can post it, can I?
                  Great! I am certainly interested. You could use http://www.yousendit.com/ to send me the files. My email address is arjenp at interface21 dot com.

                  Originally posted by benethridge
                  Arjen, in hindsight, i.e. having gotten the airline sample running ok, the Ivy and the multiple build files might make things easy on you Spring core developers, but they make it hard on us new to Spring, coz we have to go through multiple learning curves at once, making it very hard to figure out if the problem is in our code, the Spring code, the Ivy code, the JAXB code, the Ant code, the Sun code, the Eclipse, and on and on. Each of these comes with its own learning curve and "issues" (quirks and gotcha's).
                  Yes, I've found Ivy to be quite difficult to grasp at some times as well. That's one of the reasons I've switched to Maven 2. It's becoming more and more of a standard now, and offers nice things like creating an Eclipse workspace from the project descriptor, to get people started.

                  Originally posted by benethridge
                  Since I really like the Spring Web Service model, and I want it to succeed, and be well-accepted quickly by the java community, it might make that acceptance go faster if the Spring team could remove some of the "variables" in the sample apps. On this I speak with some authority, having been a very successful flight instructor for many years. (Lots of fun but VERY little money in that profession. ). As a teacher, one often has to break down the complex into simple learnable units, not for the benefit of the teacher, but for the benefit of the student...which ultimately "benefits" the teacher as well, now that I think of it.
                  I see your point. You must understand that you are in fact the "early adaptors" of this project. After the Spring 2.0 release, Rick Evans, who also wrote most of the Spring 2.0 reference documentation, will devote some of his time to write more docs for Spring-WS. I do love the fact that the project already has such a loyal backing.

                  In the near future, I will devote more time to make common things easier. Now that there actually people using Spring-WS, this can be done. I'm open for suggestions on this, though. You, after all, are the users, and you can decide the future of this project.

                  Cheers,

                  Comment


                  • #10
                    Hi, Arjen.

                    I sent this to you via yousendit.com.

                    The maven2 sounds promising, but heads-up that the user feedback on it indicates that there may still be significant bugs:

                    http://www.javaworld.com/javaworld/j...-maven-p3.html

                    Also I worry that maven2 may be yet another third-party tool that will add to the learning complexity (though granted that in general these tools are great once one is through the learning curve of Spring itself).

                    I accept the fact that I'm an "early adapter". To me, from a design point of view Spring WS looks like the best thing on the market today. If you can keep the pattern examples simple to deploy into IDEs, I think it will self-propel into a market leader.

                    Ben

                    Comment


                    • #11
                      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

                      Comment


                      • #12
                        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.

                        Comment


                        • #13
                          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

                          Comment

                          Working...
                          X