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

3

6

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.

Smoothspoken answered 19/6, 2012 at 19:20 Comment(3)
The answer is "it depends" :) Your best bet is to fire up your favorite IDE (perhaps Eclipse J2EE, perhaps something else), code up a little Java interface, push the "convert to WSDL" button ... and see what happens. Then, if it doesn't barf .. see if the resulting WSDL is something you can use with all your clients (perhaps Axis, perhaps Axis2, perhaps .Net, perhaps something else entirely). Good luck!Ponton
id=1 - is ID from class book or Integer from HashMap?Islam
id is from class book. I don't know exactly how the xml response should look like. but I'd like those instance fields in book object shown in return tags.Smoothspoken
E
3

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

Erumpent answered 20/6, 2012 at 8:20 Comment(0)
B
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

Blew answered 19/6, 2012 at 21:2 Comment(11)
Your suggestion is very vague. Please elaborate or edit on "the information required". I will vote as not useful until you can provide a better answer. Thanks!Cover
@Paul-SebastianManole:I have no idea what are you talking about. I think the statement is pretty clearBlew
Well, it makes pretty much no sense to me. I mean, OK, I don't know a lot about JAX-WS but returning Java "constructs" like simple objects and Collections works. JAXB does its job. After reading a bit more this week, I realized I might need to create specific class types with correct annotations for JAXB to convert to proper XML. Am I right or am I wrong? And please provide more explanation this time, also regarding what you meant in your answer by "the information required so that the web service client can build the hash table regardless of the programming language it is written".Cover
@Paul-SebastianManole:I would suggest that you open a new question with exactly the problem you have.Because now I am not sure what is your question.Do you have the same problem as the OP?Blew
My problem was and is exactly the same as the OP's. But never mind.Cover
@Paul-SebastianManole:The OP tries to use a hashmap. As already said language specific constructs should not be exposed from a Web Services. If you are doing that you are misusing web services. You can e.g. return to the client an array of objects and the client can do what them what it needs e.g. create a hash map.Blew
So you can return an array of ambiguous objects but not a hash map?Cover
@Paul-SebastianManole:I am not sure what you mean ambiguous objects.If you need the semantics of a hash table, a hash table can be "captured" by a list of items. The precondition is that the size of the list is even. To construct the hash table you just loop over the list using the items in even position as the key (0,2,4 etc) and the items in the even position (1,3,4 etc) as the value. What I am trying to say is that Web Services is not meant to capture any language specific constructs, business classes etc. Use it for what it isBlew
@Paul-SebastianManole: (an interconnection/interoperability of diverse systems via exchanging data-holder objects) and you will not only be doing it right, but save yourself a lot of troublesBlew
I was expecting that SOAP (and hence JAX-WS) could handle a Map. I understand the reasoning why not, but I expected it.Lodovico
The dude is enraged. Consider MapFadden
K
1

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.

Kierkegaardian answered 17/7, 2014 at 17:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.