JAX-WS:如何使SOAP响应返回HashMap对象

6

我有一个简单的Web服务:

    @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;
    }

书籍类也很简单:

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;
    }
}

现在当您在浏览器的测试器中调用此Web服务时,我会收到以下内容:
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>


是否可以在<return>标签中显示返回的HashMap对象,例如:

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

我之所以想要在返回标记中获取值,是因为从客户端方面来看,我在网页中使用jQuery AJAX调用此web服务,而我得到的响应XML只是空的<return>标记。那么如何从AJAX客户端获取真正的书籍价值呢?
以下是我的AJAX Web代码:
   $.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
   }
}

我测试了一个简单的“Hello World”网络服务,它运行良好。


答案是“这要看情况” :) 你最好启动你最喜欢的IDE(比如Eclipse J2EE,或者其他什么),编写一个小的Java接口,按下“转换为WSDL”按钮...然后看看会发生什么。然后,如果它没有出错...看看生成的WSDL是否可以与所有客户端一起使用(例如Axis、Axis2、.Net、或者完全不同的东西)。祝你好运! - paulsm4
id=1 - 是来自类 Book 的 ID 还是 HashMap 中的 Integer? - Ilya
id 是来自类别 book。我不确定 XML 响应应该是什么样子的,但我希望 book 对象中的这些实例字段显示在返回标签中。 - neo
3个回答

3
为了帮助JAXB,您可以将HashMap包装在一个类中,并使用@XmlJavaTypeAdapter对地图进行自定义的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;
    }

}

接着可以将这个类作为你的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;
    }

毕竟,您需要实现适配器MapAdapter。有几种方法可以做到这一点,因此我建议您查看此链接


2

JAX-WS如何使SOAP响应返回HashMap对象

您不应该通过Web服务公开任何Java特定构造,例如HashMap。
Web服务是关于互操作性的,遵循您的路径是错误的方法。
只返回所需信息,以便Web服务客户端可以构建哈希表,而无论它使用的编程语言是什么。


您的建议非常笼统。请详细说明或编辑“所需信息”。在您能提供更好的答案之前,我将投票为无用。谢谢! - Paul-Sebastian Manole
3
@Paul-SebastianManole:我不知道你在说什么。我认为这个陈述非常清楚。 - Cratylus
2
@Paul-SebastianManole:OP试图使用哈希表。正如已经提到的,特定于语言的结构不应该从Web服务中公开。如果你这样做了,那么你正在滥用Web服务。你可以例如将对象数组返回给客户端,客户端可以根据自己的需求进行操作,比如创建一个哈希表。 - Cratylus
1
@Paul-SebastianManole:我不确定你所说的“模糊对象”是什么意思。如果你需要哈希表的语义,哈希表可以通过一个项目列表来“捕获”。前提条件是列表的大小是偶数。要构建哈希表,只需循环遍历列表,使用偶数位置的项目作为键(0、2、4等),使用奇数位置的项目(1、3、5等)作为值。我的意思是Web服务并不意味着要捕获任何特定于语言的结构、业务类等。用它来实现它的功能。 - Cratylus
1
我本来以为SOAP(因此也包括JAX-WS)可以处理Map。我理解为什么不能,但我还是有这个期望的。 - Thorbjørn Ravn Andersen
显示剩余6条评论

1
我在JBoss论坛上找到了一种解决方案,对于我在Glassfish上有效。原始解决方案在JBoss Forum, topic from Allesio Soldano中。它由一个辅助类组成,该类具有HashMap作为嵌套类型,即HashMap<String,String>。然后在Web服务类中,此辅助类用作返回值。注释@XmlAccessorType(XmlAccessType.FIELD)确保结构将被SOAP正确处理在SOAP响应中。
@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);
  }
}

在Webservice中,直接将此类用作返回对象,无需进行任何其他设置。当然,必须首先创建对象并填充映射,方式与另一个POJO类似。
如果HashMap由另一个非原始类型(对象)组成,则我证明可以递归地在嵌套的复杂对象上使用相同的方法。规则是,类不是继承的,即它必须作为属性嵌套,并且最后一个类具有所有原始属性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接