JAX-WS: How to make a SOAP Response return a HashMap object

25,179

Solution 1

In order to help JAXB, you can 'wrap' your HashMap in a class and use the @XmlJavaTypeAdapter to make your custom serialization of the map to XML.

public class Response {

    @XmlJavaTypeAdapter(MapAdapter.class)    
    HashMap<Integer, Book> books;

    public HashMap<Integer, Book> getBooks() {
        return mapProperty;
    }

    public void setBooks(HashMap<Integer, Book> map) {
        this.mapProperty = map;
    }

}

Then use this class as a return value of your WebMethod

@WebMethod(operationName="getBookList")
    public Response getBookList()
    {
         HashMap<Integer, Book> books = new HashMap<Integer,Book>();
         Book b1 = new Book(1,"title1");
         Book b2 = new Book(2, "title2");
         books.put(1, b1);
         books.put(2, b2);
         Response resp = new Response();
         resp.setBooks(books);
         return resp;
    }

After all, you need to implement your adapter MapAdapter. There is several ways to do this, so I recommend you to check this

Solution 2

JAX-WS How to make SOAP Response return Hashmap object

You should not expose any Java specific constructs like HashMap via a Web Service.
Web Services is about interoperability and following paths like yours is the wrong way.
Just return the information required so that the web service client can build the hash table regardless of the programming language it is written

Solution 3

On JBoss Forum I found solution, which works for me on Glassfish. Original solution is on JBoss Forum, topic from Allesio Soldano. It consists from one auxiliary class, which has a HashMap as nested type i.e. HashMap<String, String>. Than in web service Class this auxiliary class is used as returning value. The annotation @XmlAccessorType(XmlAccessType.FIELD) ensures, that structure will be properly treated by SOAP in SOAP Response.

@XmlAccessorType(XmlAccessType.FIELD)
public class MyHash {
  protected HashMap<String,String> realMap;

  // constructor
  public MyHash() {
    realMap = new HashMap<String,String>();
  }

  /**
   * @return HashMap<String,String>
   */
  public HashMap<String,String> getRealMap() {  
    if (realMap==null) {  
      realMap = new HashMap<String,String>();  
    }
    return realMap;  
  }

  /**
   * @param key
   * @param value
   */
  public void put(String key, String value) {
    realMap.put(key, value);
  }
}

In Webservice use this class directly as a return object without any additional settings. Of course, the object must be first created and map should be filled similarly as in another POJO.

If HashMap consists from another non primitive types (objects), I proofed, that it is possible to recursively use the same manner on the nested complex objects. The rule is, that class is not inherited i.e. it must be nested as attribute and the last class has all attributes primitive.

Share:
25,179
neo
Author by

neo

Updated on July 19, 2020

Comments

  • neo
    neo almost 4 years

    So I have a simple web service:

        @WebMethod(operationName="getBookList")
        public HashMap<Integer,Book> getBookList()
        {
            HashMap<Integer, Book> books = new HashMap<Integer,Book>();
             Book b1 = new Book(1,"title1");
             Book b2 = new Book(2, "title2");
             books.put(1, b1);
             books.put(2, b2);
            return books;
        }
    

    The book class is also simple:

    public class Book
    {
        private int id;
        private String title;
    
        public int getId()
        {
            return id;
        }
    
        public String getTitle()
        {
            return title;
        }
        public Book(int id, String title)
        {
            id = this.id;
            title = this.title;
        }
    }
    

    Now when you call this web service in browser's tester, I get:

    Method returned
    my.ws.HashMap : "my.ws.HashMap@1f3cf5b"
    
    SOAP Request
      ...
      ...
    
    SOAP Response
    
    <?xml version="1.0" encoding="UTF-8"?>
    <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
        <S:Body>
            <ns2:getBookListResponse xmlns:ns2="http://ws.my/">
                <return/>
            </ns2:getBookListResponse>
        </S:Body>
    </S:Envelope>
    


    Is it possible to have the returned HashMap object shown in <return> tag, something like

    <return>
         <Book1>
              id=1
              title=title1
         </Book1>
    </return>
    <return>
         <Book2>
              id=2
              title=title2
         </Book2>
    </return>
    

    The reason why I want the values in return tags is because, from client side, I am using jQuery AJAX in a web page to call this web service, and the response XML I am getting is just empty <return> tags. How do I ever get the real book value from AJAX client side?

    Here's my AJAX web code:

       $.ajax({
            url: myUrl, //the web service url
            type: "POST",
            dataType: "xml",
            data: soapMessage, //the soap message. 
            complete: showMe,contentType: "text/xml; charset=\"utf-8\""         
    
        });
    function showMe(xmlHttpRequest, status)
    {  (xmlHttpRequest.responseXML).find('return').each(function()
       { // do something
       }
    }
    

    I tested with simple hello world web service and it worked.