9 Replies Latest reply on Jan 16, 2018 7:36 PM by simonkao2714

    Soap service returning complex objects(Such as hashmaps) inc

    mwkohout

      Hello All.

      I've got a soap service(which is also a seam component) with a method that returns a hashmap. Through debugging I know that my method is returning a valid set of java objects but from client code( Ruby and Java) all I'm getting is a null value. Other methods that return simple strings or return an array of Longs work perfectly.

      as far as my platform I'm running on jboss 4.2.1GA with Seam 2.0.0GA.

      here's the relevant server code. The first method is one that works incorrectly and the bottom two work:

      @WebService()
      @SOAPBinding(
       parameterStyle=SOAPBinding.ParameterStyle.BARE, style=SOAPBinding.Style.RPC)
      //@SOAPBinding(style = SOAPBinding.Style.RPC)
      @Name("StudyServiceWS")
      @Scope(value=ScopeType.STATELESS)
      @Stateless
      public class StudyService implements StudyServiceRemote{
      
      //this is a test method that currently returns a null to the client
       @WebMethod
       public HashMap getHashMap( String key, String value)
       {
       HashMap m = new HashMap();
       m.put( key, value);
       return m;
       }
      //this method works
      @WebMethod()
      public String echo( @WebParam(name = "echo")String echo)
      {
       return echo;
      }
      //this also works
      @WebMethod
       public Long[] getStudyIDs( String x500)
       {
       Long[] returnIDs = null;
       UserHome userHome = (UserHome)Component.getInstance(
       UserHome.class, true);
       User user = userHome.findByInternetID(x500);
      
       ......
      
       return returnIDs;
       }
      
      


      generated wsdl:
      <definitions name='StudyServiceService' targetNamespace='http://webService.core.ictr.umn.edu/' xmlns='http://schemas.xmlsoap.org/wsdl/' xmlns:ns1='http://jaxb.dev.java.net/array' xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/' xmlns:tns='http://webService.core.ictr.umn.edu/' xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
       <types>
       <xs:schema targetNamespace='http://webService.core.ictr.umn.edu/' version='1.0' xmlns:xs='http://www.w3.org/2001/XMLSchema'>
       <xs:complexType name='hashMap'>
       <xs:complexContent>
       <xs:extension base='ns1:abstractMap' xmlns:ns1='http://webService.core.ictr.umn.edu/'>
       <xs:sequence/>
       </xs:extension>
       </xs:complexContent>
      
       </xs:complexType>
       <xs:complexType abstract='true' name='abstractMap'/>
       <xs:complexType name='arrayList'>
       <xs:complexContent>
       <xs:extension base='ns2:abstractList' xmlns:ns2='http://webService.core.ictr.umn.edu/'>
       <xs:sequence/>
       </xs:extension>
       </xs:complexContent>
       </xs:complexType>
      
       <xs:complexType abstract='true' name='abstractList'>
       <xs:complexContent>
       <xs:extension base='ns3:abstractCollection' xmlns:ns3='http://webService.core.ictr.umn.edu/'>
       <xs:sequence/>
       </xs:extension>
       </xs:complexContent>
       </xs:complexType>
       <xs:complexType abstract='true' name='abstractCollection'/>
       </xs:schema>
      
       <xs:schema targetNamespace='http://jaxb.dev.java.net/array' version='1.0' xmlns:xs='http://www.w3.org/2001/XMLSchema'>
       <xs:complexType final='#all' name='longArray'>
       <xs:sequence>
       <xs:element maxOccurs='unbounded' minOccurs='0' name='item' nillable='true' type='xs:long'/>
       </xs:sequence>
       </xs:complexType>
       </xs:schema>
       </types>
       <message name='StudyService_getHashMap'>
      
       <part name='arg0' type='xsd:string'></part>
       <part name='arg1' type='xsd:string'></part>
       </message>
       <message name='StudyService_getStudyIDs'>
       <part name='arg0' type='xsd:string'></part>
       </message>
       <message name='StudyService_getSubjects'>
       <part name='arg0' type='xsd:long'></part>
       </message>
      
       <message name='StudyService_getSubjectsResponse'>
       <part name='return' type='tns:arrayList'></part>
       </message>
       <message name='StudyService_getStudies'>
       <part name='x500' type='xsd:string'></part>
       </message>
       <message name='StudyService_getStudy'>
       <part name='arg0' type='xsd:string'></part>
       <part name='arg1' type='xsd:long'></part>
      
       </message>
       <message name='StudyService_echo'>
       <part name='echo' type='xsd:string'></part>
       </message>
       <message name='StudyService_getStudyResponse'>
       <part name='return' type='tns:hashMap'></part>
       </message>
       <message name='StudyService_getStudyIDsResponse'>
       <part name='return' type='ns1:longArray'></part>
      
       </message>
       <message name='StudyService_getSubjectsStringOperation'>
       <part name='arg0' type='xsd:string'></part>
       </message>
       <message name='StudyService_getStudiesResponse'>
       <part name='return' type='tns:hashMap'></part>
       </message>
       <message name='StudyService_getSubjectsStringOperationResponse'>
       <part name='return' type='tns:arrayList'></part>
      
       </message>
       <message name='StudyService_echoResponse'>
       <part name='return' type='xsd:string'></part>
       </message>
       <message name='StudyService_getHashMapResponse'>
       <part name='return' type='tns:hashMap'></part>
       </message>
       <portType name='StudyService'>
       <operation name='echo' parameterOrder='echo'>
      
       <input message='tns:StudyService_echo'></input>
       <output message='tns:StudyService_echoResponse'></output>
       </operation>
       <operation name='getHashMap' parameterOrder='arg0 arg1'>
       <input message='tns:StudyService_getHashMap'></input>
       <output message='tns:StudyService_getHashMapResponse'></output>
       </operation>
       <operation name='getStudies' parameterOrder='x500'>
       <input message='tns:StudyService_getStudies'></input>
      
       <output message='tns:StudyService_getStudiesResponse'></output>
       </operation>
       <operation name='getStudy' parameterOrder='arg0 arg1'>
       <input message='tns:StudyService_getStudy'></input>
       <output message='tns:StudyService_getStudyResponse'></output>
       </operation>
       <operation name='getStudyIDs' parameterOrder='arg0'>
       <input message='tns:StudyService_getStudyIDs'></input>
       <output message='tns:StudyService_getStudyIDsResponse'></output>
      
       </operation>
       <operation name='getSubjects' parameterOrder='arg0'>
       <input message='tns:StudyService_getSubjects'></input>
       <output message='tns:StudyService_getSubjectsResponse'></output>
       </operation>
       <operation name='getSubjectsStringOperation' parameterOrder='arg0'>
       <input message='tns:StudyService_getSubjectsStringOperation'></input>
       <output message='tns:StudyService_getSubjectsStringOperationResponse'></output>
       </operation>
      
       </portType>
       <binding name='StudyServiceBinding' type='tns:StudyService'>
       <soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/>
       <operation name='echo'>
       <soap:operation soapAction=''/>
       <input>
       <soap:body namespace='http://webService.core.ictr.umn.edu/' use='literal'/>
       </input>
       <output>
      
       <soap:body namespace='http://webService.core.ictr.umn.edu/' use='literal'/>
       </output>
       </operation>
       <operation name='getHashMap'>
       <soap:operation soapAction=''/>
       <input>
       <soap:body namespace='http://webService.core.ictr.umn.edu/' use='literal'/>
       </input>
       <output>
      
       <soap:body namespace='http://webService.core.ictr.umn.edu/' use='literal'/>
       </output>
       </operation>
       <operation name='getStudies'>
       <soap:operation soapAction=''/>
       <input>
       <soap:body namespace='http://webService.core.ictr.umn.edu/' use='literal'/>
       </input>
       <output>
      
       <soap:body namespace='http://webService.core.ictr.umn.edu/' use='literal'/>
       </output>
       </operation>
       <operation name='getStudy'>
       <soap:operation soapAction=''/>
       <input>
       <soap:body namespace='http://webService.core.ictr.umn.edu/' use='literal'/>
       </input>
       <output>
      
       <soap:body namespace='http://webService.core.ictr.umn.edu/' use='literal'/>
       </output>
       </operation>
       <operation name='getStudyIDs'>
       <soap:operation soapAction=''/>
       <input>
       <soap:body namespace='http://webService.core.ictr.umn.edu/' use='literal'/>
       </input>
       <output>
      
       <soap:body namespace='http://webService.core.ictr.umn.edu/' use='literal'/>
       </output>
       </operation>
       <operation name='getSubjects'>
       <soap:operation soapAction=''/>
       <input>
       <soap:body namespace='http://webService.core.ictr.umn.edu/' use='literal'/>
       </input>
       <output>
      
       <soap:body namespace='http://webService.core.ictr.umn.edu/' use='literal'/>
       </output>
       </operation>
       <operation name='getSubjectsStringOperation'>
       <soap:operation soapAction=''/>
       <input>
       <soap:body namespace='http://webService.core.ictr.umn.edu/' use='literal'/>
       </input>
       <output>
      
       <soap:body namespace='http://webService.core.ictr.umn.edu/' use='literal'/>
       </output>
       </operation>
       </binding>
       <service name='StudyServiceService'>
       <port binding='tns:StudyServiceBinding' name='StudyServicePort'>
       <soap:address location='http://127.0.0.1:8080/StudyServiceService/StudyService'/>
       </port>
       </service>
      
      </definitions>
      


      Any ideas? Any suggestion or 4 letter word would be welcome.

        • 1. Re: Soap service returning complex objects(Such as hashmaps)
          mendaye

          I came across similar issue before and I think I used Document/Literal binding to resolve it. You can try by using the following SOAPBinding...
          @SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use=SOAPBinding.Use.LITERAL)

          • 2. Re: Soap service returning complex objects(Such as hashmaps)
            mwkohout

            at least in my instance I get the same result as before.

            btw, I'm running the version javaws that comes default with jboss 4.2.1GA. I don't suppose this annotation change fixed your issue because you were on the new version of jbossws?

            I suppose the next step is to see if it's a parsing error or just a bad response by capturing the envelope in my log.

            huh. this is the call that would return a hashmap with one key/value pair in it. To my untrained eyes there isn't anything in the response.

            17:12:18,874 DEBUG [SOAPContentElement] -----------------------------------
            17:12:18,874 DEBUG [SOAPContentElement] Transitioning from OBJECT_VALID to XML_VALID
            17:12:18,874 DEBUG [ObjectContent] getXMLFragment from Object [xmlType={http://webService.core.ictr.umn.edu/}hashMap,javaType=class java.util.HashMap]
            17:12:18,874 DEBUG [JAXBSerializer] serialize: [xmlName=return,xmlType={http://webService.core.ictr.umn.edu/}hashMap]
            17:12:18,874 DEBUG [JAXBSerializer] serialized: <return/>
            17:12:18,874 DEBUG [ObjectContent] xmlFragment: [source=<return/>]
            17:12:18,874 DEBUG [SOAPContentElement] -----------------------------------
            17:12:18,875 TRACE [MessageTrace] Outgoing Response Message
            <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
             <env:Header>
             <seam:conversationId xmlns:seam='http://www.jboss.org/seam/webservice'>6</seam:conversationId>
             </env:Header>
             <env:Body>
             <n1:getStudiesResponse xmlns:n1='http://webService.core.ictr.umn.edu/'>
             <return/>
             </n1:getStudiesResponse>
             </env:Body>
            </env:Envelope>
            


            • 3. Re: Soap service returning complex objects(Such as hashmaps)
              asoldano

              This is basically a JAXB bug https://jaxb.dev.java.net/issues/show_bug.cgi?id=268.

              The workaround you can use it to wrap your map into another class. This class has to be annotated with @XmlAccessorType(XmlAccessType.FIELD) since the bug prevents you from adding @XmlElement to your map field.

              @XmlAccessorType(XmlAccessType.FIELD)
              public class MyMap {
              
               protected HashMap<String,String> realMap;
              
               public HashMap<String,String> getRealMap() {
               if (realMap==null) {
               realMap = new HashMap<String,String>();
               }
               return realMap;
               }
              }
              
              ...
              
              @WebMethod
              public MyMap getHashMap( String key, String value) {
               ...
              }
              


              • 4. Re: Soap service returning complex objects(Such as hashmaps)
                mwkohout

                This absolutely works so long as it's a simple Map with simple objects(like strings) as key/values. But this seems to break down when you've got nested maps.

                here's a "simple" map with just a string key and string value.

                <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
                 <env:Header>
                 <seam:conversationId xmlns:seam='http://www.jboss.org/seam/webservice'>6</seam:conversationId>
                 </env:Header>
                 <env:Body>
                 <n1:getHashMapResponse xmlns:n1='http://webService.core.ictr.umn.edu/'>
                 <return>
                 <realMap>
                 <entry>
                 <key xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:type='xs:string'>mike</key>
                 <value xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:type='xs:string'>kohout</value>
                 </entry>
                 </realMap>
                 </return>
                 </n1:getHashMapResponse>
                 </env:Body>
                </env:Envelope>
                


                here's the results from a call that returns an list of Maps/MyMaps, where each of the Maps/MyMaps has a property that also contains a list of MyMaps. So it's an ArrayList where each MyMap can contain a nested ArrayList.
                It's still returning an empty response.

                <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
                 <env:Header>
                 <seam:conversationId xmlns:seam='http://www.jboss.org/seam/webservice'>5</seam:conversationId>
                 </env:Header>
                 <env:Body>
                 <n1:getSubjectsResponse xmlns:n1='http://webService.core.ictr.umn.edu/'>
                 <return/>
                 </n1:getSubjectsResponse>
                 </env:Body>
                </env:Envelope>
                


                Any other suggestions to make this work?
                I'm using maps and lists to avoid making DTOs. Maybe at this point it would just be easier to make the damn DTOs.

                • 5. Re: Soap service returning complex objects(Such as hashmaps)
                  asoldano

                   

                  "mwkohout" wrote:
                  This absolutely works so long as it's a simple Map with simple objects(like strings) as key/values. But this seems to break down when you've got nested maps.
                  ...
                  I'm using maps and lists to avoid making DTOs. Maybe at this point it would just be easier to make the damn DTOs.


                  Well, I'm sorry I have no other suggestion; considering the workaround is practically to create a wrap for each map... and you have a map-hell there ;-) ... I would use the DTOs, at least this keep your model clearer.

                  • 6. Re: Soap service returning complex objects(Such as hashmaps)
                    mwkohout

                    Yeah, I think you're right....thanks for your help by the way.

                    • 7. Re: Soap service returning complex objects(Such as hashmaps) inc
                      gundasiva

                      A wrapper class with a hashmap type should be created and used in the webservice

                       

                       

                      package com.abc.dto;

                       

                      import java.util.HashMap;

                      import javax.xml.bind.annotation.XmlRootElement;

                       

                      @XmlRootElement

                      public class HashMapWrapper {

                       

                          private HashMap<String, String> realMap = new HashMap<String, String>();

                       

                          public HashMapWrapper(){

                       

                          }

                       

                          public void setRealMap(HashMap<String, String> realMap) {

                              this.realMap = realMap;

                          }

                       

                          public HashMap<String, String> getRealMap() {

                              return realMap;

                          }

                       

                      }

                       

                      creation of webservice

                       

                      @WebMethod(operationName="returnHashMap")

                          @WebResult(name="hashMapWrapper")

                          public HashMapWrapper returnHashMap(@WebParam(name="abc") String abc) throws MywebServiceException {

                         }

                       

                      generated wsdl

                       

                      <xs:complexType name="returnHashMap">

                              <xs:sequence>

                                <xs:element minOccurs="0" name="hashMapWrapper" type="tns:hashMapWrapper"/>

                              </xs:sequence>

                            </xs:complexType>

                            <xs:complexType name="hashMapWrapper">

                              <xs:sequence>

                                <xs:element name="realMap">

                                  <xs:complexType>

                                    <xs:sequence>

                                      <xs:element maxOccurs="unbounded" minOccurs="0" name="entry">

                                        <xs:complexType>

                                          <xs:sequence>

                                            <xs:element minOccurs="0" name="key" type="xs:string"/>

                                            <xs:element minOccurs="0" name="value" type="xs:string"/>

                                          </xs:sequence>

                                        </xs:complexType>

                                      </xs:element>

                                    </xs:sequence>

                                  </xs:complexType>

                                </xs:element>

                              </xs:sequence>

                            </xs:complexType>

                       

                       

                       

                       

                       

                      • 8. Re: Soap service returning complex objects(Such as hashmaps) inc
                        hariprasad108

                        Hello Alessio, I verified your solution on Glassfish. Works properly.

                        • 9. Re: Soap service returning complex objects(Such as hashmaps) inc
                          simonkao2714

                          Hi All,

                           

                          This solution works s for me too.

                          I have been stuck for two days on how to pass the hashMap type to my Web Service.

                           

                          Thanks a lot for your help !!!

                           

                          Samuel

                           

                          My Wrapper class:

                           

                          import java.io.Serializable;

                          import javax.xml.bind.annotation.XmlElement;

                          import javax.xml.bind.annotation.XmlAccessorType;

                          import javax.xml.bind.annotation.XmlAccessType;

                          import java.util.HashMap;

                          import javax.xml.bind.annotation.XmlRootElement;

                           

                          @XmlRootElement

                          public class DMapWrapper  implements Serializable{

                              private static final long serialVersionUID = 5953679585221438073L;

                           

                              protected HashMap<String, String> map = new HashMap<String, String>();

                           

                              public DMapWrapper()

                              {

                              }

                           

                              public void setRealMap(HashMap<String, String> map) {

                                  this.map = map;

                              }

                           

                              public HashMap<String, String> getRealMap() {

                           

                                  return map;

                              }

                                 

                          }

                           

                           

                          My Web Service code :

                           

                          @SuppressWarnings("rawtypes")

                              @WebMethod

                              public String Mycaller(@WebParam(name = "mesServerURL") String mesServerURL,

                                      @WebParam(name = "mesLogin") String mesLogin,

                                      @WebParam(name = "mesPassword") String mesPassword,

                                      @WebParam(name = "orderNumber") String orderNumber,

                                      @WebParam(name = "materialPendingMap") DMapWrapper materialPendingMap,

                                      ) throws ServiceException {

                          ........................

                          ........................

                          .......................

                          }

                           

                          <xs

                          My WSDL:

                          -<xs:complexType name="dMapWrapper">

                          -<xs:sequence>

                          -<xs:element name="realMap">

                          -<xs:complexType>

                          -<xs:sequence>

                          -<xs:element name="entry" minOccurs="0" maxOccurs="unbounded">

                          -<xs:complexType>

                          -<xs:sequence>

                          <xs:element name="key" type="xs:string" minOccurs="0"/>

                          <xs:element name="value" type="xs:string" minOccurs="0"/>

                          </xs:sequence>

                          </xs:complexType>

                          </xs:element>

                          </xs:sequence>

                          </xs:complexType>

                          </xs:element>

                          </xs:sequence>

                          </xs:complexType>