5 Replies Latest reply on Apr 29, 2008 9:14 PM by soch

    Newbee Q: Returning hashmaps

    soch

      I am trying to take the simple echo example (http://jbws.dyndns.org/mediawiki/index.php?title=JBossWS_JAX-WS_Tools) to the next level and running into problem.

      I want to return a hashmap instead of the string.

      Instead of the client printing the hasmap contents it prints the address of the the hashmap.

      I am using the new tools: wsconsume, wsprovide & wsrunclient.

      Here's the code:


      GetPM.java:
      =========

      package getpm;
      
      import java.util.HashMap;
      
      @javax.jws.WebService
      public class GetPM
      {
      
      HashMap map = new HashMap();
      
      public HashMap getPM()
      {
      map.put("key1", "value1");
      map.put("key2", "value2");
      map.put("key3", "value3");
      System.out.println("From Server:" + map.toString());
      return map;
      }
      }

      I am using the same web.xml as in the echo example -- is this were I am going wrong?

      web.xml
      =======
      <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
      version="2.4">
      
      <servlet>
      <servlet-name>GetPM</servlet-name>
      <servlet-class>getpm.GetPM</servlet-class>
      </servlet>
      
      <servlet-mapping>
      <servlet-name>GetPM</servlet-name>
      <url-pattern>/GetPM</url-pattern>
      </servlet-mapping>
      </web-app>



      I created the getpm.war file & deployed it on the jboss AS.

      Using wsconsume created the client files using the online version of service wsdl file: wsconsume -k http://localhost:8080/getpm/GetPM?wsdl

      The client then calls the service using the following

      GetPMclient.java:
      =============
      import getpm.*;
      
      public class GetPMclient
      {
      public static void main(String args[])
      {
      GetPMService service = new GetPMService();
      GetPM pm = service.getGetPMPort();
      System.out.println("Server said: " + pm.getPM());
      
      //HashMap hm = (HashMap) pm.getPM();
      //System.out.println(hm.toString());
      }
      }


      On the server stdout I get the hashmap printed correctly, but on the client side instead of the hashmap I get the reference of the hashmap as below:

      getpm.HashMap@1a0b53e

      instead of

      {key1=value1, key2=value2, key3=value3}


      C:\....\webservices\getpm\client\output>wsrunclient GetPMclient
      log4j:WARN No appenders could be found for logger (org.jboss.ws.metadata.builder.jaxws.JAXWSWebServiceMetaDataBuilder).
      log4j:WARN Please initialize the log4j system properly.
      Server said:
      getpm.HashMap@1a0b53e

        • 1. Re: Newbee Q: Returning hashmaps
          mikkus

          toString() outputs the contents of the HashMap only if the class generated is actually a HashMap, otherwise it outputs the java class instance name.

          Most probably, wsconsume generated a class named HashMap, instead of using java.util.HashMap. This class is not actually a hashmap but a representation of the web service return data. Most probably, you'll need to convert that data to an actual hashmap.

          I notice you commented out the cast to java.util.HashMap, probably you got a ClassCastException here? Seeing the class generated by wsconsume and related wsdl would help.

          Your web.xml file should not be the problem. It just exposes the webservice, and since you're able to invoke it, it is doing its job.

          • 2. Re: Newbee Q: Returning hashmaps
            soch

             

            "mikkus" wrote:
            toString() outputs the contents of the HashMap only if the class generated is actually a HashMap, otherwise it outputs the java class instance name.

            Most probably, wsconsume generated a class named HashMap, instead of using java.util.HashMap. This class is not actually a hashmap but a representation of the web service return data. Most probably, you'll need to convert that data to an actual hashmap.

            I notice you commented out the cast to java.util.HashMap, probably you got a ClassCastException here? Seeing the class generated by wsconsume and related wsdl would help.

            Your web.xml file should not be the problem. It just exposes the webservice, and since you're able to invoke it, it is doing its job.


            Thanks mikkus. Yes, wsconsume creates it's own HashMap which inherits from it's own AbstractMap.

            How do I convert the wsconsume generated HashMap to java.util.HashMap? I believe this needs to be done at the client side.

            Data below:

            C:\..\test\webservices> wsconsume -k http://localhost:8080/getpm/GetPM?wsdl
            JBossWS-Native stack deployed
            parsing WSDL...
            generating code...
            getpm\AbstractMap.java
            getpm\GetPM.java
            getpm\GetPMResponse.java
            getpm\GetPMService.java
            getpm\GetPM_Type.java
            getpm\HashMap.java
            getpm\ObjectFactory.java
            getpm\package-info.java

            HashMap.java:
            package getpm;
            
            import javax.xml.bind.annotation.XmlAccessType;
            import javax.xml.bind.annotation.XmlAccessorType;
            import javax.xml.bind.annotation.XmlType;
            
            
            /**
             * <p>Java class for hashMap complex type.
             *
             * <p>The following schema fragment specifies the expected content contained within this class.
             *
             * <pre>
             * <complexType name="hashMap">
             * <complexContent>
             * <extension base="{http://getpm/}abstractMap">
             * <sequence>
             * </sequence>
             * </extension>
             * </complexContent>
             * </complexType>
             * </pre>
             *
             *
             */
            @XmlAccessorType(XmlAccessType.FIELD)
            @XmlType(name = "hashMap")
            public class HashMap
             extends AbstractMap
            {
            
            
            }


            AbstractMap.java:

            package getpm;
            
            import javax.xml.bind.annotation.XmlAccessType;
            import javax.xml.bind.annotation.XmlAccessorType;
            import javax.xml.bind.annotation.XmlType;
            
            
            /**
             * <p>Java class for abstractMap complex type.
             *
             * <p>The following schema fragment specifies the expected content contained within this class.
             *
             * <pre>
             * <complexType name="abstractMap">
             * <complexContent>
             * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
             * <sequence>
             * </sequence>
             * </restriction>
             * </complexContent>
             * </complexType>
             * </pre>
             *
             *
             */
            @XmlAccessorType(XmlAccessType.FIELD)
            @XmlType(name = "abstractMap")
            public abstract class AbstractMap {
            
            
            }


            The generated service WSDL under C:\jboss-4.2.2.GA\server\default\data\wsdl\getpm.war

            GetPMService31986.wsdl:
            <?xml version="1.0" encoding="UTF-8"?>
            <definitions name="GetPMService" targetNamespace="http://getpm/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://getpm/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
             <types>
             <xs:schema targetNamespace="http://getpm/" version="1.0" xmlns:tns="http://getpm/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
             <xs:element name="getPM" type="tns:getPM"/>
             <xs:element name="getPMResponse" type="tns:getPMResponse"/>
             <xs:complexType name="getPM">
             <xs:sequence/>
             </xs:complexType>
             <xs:complexType name="getPMResponse">
             <xs:sequence>
             <xs:element minOccurs="0" name="return" type="tns:hashMap"/>
             </xs:sequence>
             </xs:complexType>
             <xs:complexType name="hashMap">
             <xs:complexContent>
             <xs:extension base="tns:abstractMap">
             <xs:sequence/>
             </xs:extension>
             </xs:complexContent>
             </xs:complexType>
             <xs:complexType abstract="true" name="abstractMap">
             <xs:sequence/>
             </xs:complexType>
             </xs:schema>
             </types>
             <message name="GetPM_getPMResponse">
             <part name="getPMResponse" element="tns:getPMResponse">
             </part>
             </message>
             <message name="GetPM_getPM">
             <part name="getPM" element="tns:getPM">
             </part>
             </message>
             <portType name="GetPM">
             <operation name="getPM" parameterOrder="getPM">
             <input message="tns:GetPM_getPM">
             </input>
             <output message="tns:GetPM_getPMResponse">
             </output>
             </operation>
             </portType>
             <binding name="GetPMBinding" type="tns:GetPM">
             <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
             <operation name="getPM">
             <soap:operation soapAction=""/>
             <input>
             <soap:body use="literal"/>
             </input>
             <output>
             <soap:body use="literal"/>
             </output>
             </operation>
             </binding>
             <service name="GetPMService">
             <port name="GetPMPort" binding="tns:GetPMBinding">
             <soap:address location="http://127.0.0.1:8080/getpm/GetPM"/>
             </port>
             </service>
            </definitions>


            I tried the convertion but got errors:

            C:\Documents and Settings\jaina\My Documents\Work\CODE\test\webservices\getpm\output>wsrunclient GetPMclient
            log4j:WARN No appenders could be found for logger (org.jboss.ws.metadata.builder.jaxws.JAXWSWebServiceMetaDataBuilder).
            log4j:WARN Please initialize the log4j system properly.
            getpm.HashMap@1a0b53e
            C:\Documents and Settings\jaina\My Documents\Work\CODE\test\webservices\getpm\output>javac GetPMclient.java
            GetPMclient.java:13: inconvertible types
            found : getpm.HashMap
            required: java.util.HashMap
            java.util.HashMap hm = (java.util.HashMap) pm.getPM();
            ^
            1 error

            import getpm.*;
            
            import java.util.HashMap;
            
            public class GetPMclient
            {
             public static void main(String args[])
             {
            
             GetPMService service = new GetPMService();
             GetPM pm = service.getGetPMPort();
             //System.out.println("Server said: " + pm.getPM());
             java.util.HashMap hm = (java.util.HashMap) pm.getPM();
             System.out.println(hm.toString());
            
            
            
             }
            }



            • 3. Re: Newbee Q: Returning hashmaps
              mikkus

              It seems the wsdl file has an empty type for HashMap, see this:

              <xs:complexType abstract="true" name="abstractMap">
               <xs:sequence/>
               </xs:complexType>
              


              The abstractMap type contains nothing (an empty sequence). So there seems to be a problem with mapping the original type on the server side. What version on JBossWS are you using? The one that comes bundled on JBoss AS 4.2.x?

              • 4. Re: Newbee Q: Returning hashmaps
                soch

                Following are installed:
                C:\jboss-4.2.2.GA.

                C:\jbossws-3.0.1-native-2.0.4.GA --> followed the installation steps mention at http://www.jboss.org/file-access/default/members/jbossws/downloads/Install-3.0.1-native-2.0.4.GA.txt

                • 5. Re: Newbee Q: Returning hashmaps
                  soch

                  Am I supposed to use the @WebMethod annotation when returning complex datatypes?

                  The retailer e.g. at http://jbws.dyndns.org/mediawiki/index.php/Quick_Start has a method returning an object:

                  public class ProfileMgmtBean {
                  
                   @WebMethod
                   public DiscountResponse getCustomerDiscount(DiscountRequest request) {
                   return new DiscountResponse(request.getCustomer(), 10.00);
                   }
                  }