在CXF中,如果Web Service返回类型是Map的时候,比如方法签名如下
- @WebMethod
- @WebResult Map
getUserMap();
此时如果运行程序会得到类似下面的异常
- ...
- Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
- java.util.Map is an interface, and JAXB can't handle interfaces.
- this problem is related to the following location:
- at java.util.Map
- at private java.util.Map com.googlecode.garbagecan.cxfstudy.type.sample2.jaxws_asm.GetUserMapResponse._return
- at com.googlecode.garbagecan.cxfstudy.type.sample2.jaxws_asm.GetUserMapResponse
- java.util.Map does not have a no-arg default constructor.
- this problem is related to the following location:
- at java.util.Map
- at private java.util.Map com.googlecode.garbagecan.cxfstudy.type.sample2.jaxws_asm.GetUserMapResponse._return
- at com.googlecode.garbagecan.cxfstudy.type.sample2.jaxws_asm.GetUserMapResponse
- at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:102)
- at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:472)
- at com.sun.xml.bind.v2.runtime.JAXBContextImpl.
(JAXBContextImpl.java:302) - at com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1136)
- at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:154)
- at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:121)
- at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
- at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
- at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
- at java.lang.reflect.Method.invoke(Unknown Source)
- at javax.xml.bind.ContextFinder.newInstance(Unknown Source)
- at javax.xml.bind.ContextFinder.newInstance(Unknown Source)
- at javax.xml.bind.ContextFinder.find(Unknown Source)
- at javax.xml.bind.JAXBContext.newInstance(Unknown Source)
- at org.apache.cxf.jaxb.JAXBDataBinding.createContext(JAXBDataBinding.java:560)
- at org.apache.cxf.jaxb.JAXBDataBinding.createJAXBContextAndSchemas(JAXBDataBinding.java:500)
- at org.apache.cxf.jaxb.JAXBDataBinding.initialize(JAXBDataBinding.java:320)
- ... 25 more
- ...
如果把方法签名改为如下时
- @WebMethod
- @WebResult HashMap
getUserMap();
运行程序会发现返回的结果总是一个空的HashMap。
对于以上问题,此时需要对Map类型做一下数据绑定或者说转换,看下面详细例子
1. 首先是一个实体类
- package com.googlecode.garbagecan.cxfstudy.type.sample2;
- public class User {
- private String id;
- private String name;
- private String password;
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- }
2. 对Map类型做转换的类和适配器类
- package com.googlecode.garbagecan.cxfstudy.type.sample2;
- import java.util.HashMap;
- import java.util.Map;
- import javax.xml.bind.annotation.adapters.XmlAdapter;
- public class MapAdapter extends XmlAdapter
> { - @Override
- public MapConvertor marshal(Map
map) throws Exception { - MapConvertor convertor = new MapConvertor();
- for (Map.Entry
entry : map.entrySet()) { - MapConvertor.MapEntry e = new MapConvertor.MapEntry(entry);
- convertor.addEntry(e);
- }
- return convertor;
- }
- @Override
- public Map
unmarshal(MapConvertor map) throws Exception { - Map
result = new HashMap (); - for (MapConvertor.MapEntry e : map.getEntries()) {
- result.put(e.getKey(), e.getValue());
- }
- return result;
- }
- }
- package com.googlecode.garbagecan.cxfstudy.type.sample2;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Map;
- import javax.xml.bind.annotation.XmlAccessType;
- import javax.xml.bind.annotation.XmlAccessorType;
- import javax.xml.bind.annotation.XmlType;
- @XmlType(name = "MapConvertor")
- @XmlAccessorType(XmlAccessType.FIELD)
- public class MapConvertor {
- private List
entries = new ArrayList(); - public void addEntry(MapEntry entry) {
- entries.add(entry);
- }
- public List
getEntries() { - return entries;
- }
- public static class MapEntry {
- private String key;
- private Object value;
- public MapEntry() {
- super();
- }
- public MapEntry(Map.Entry
entry) { - super();
- this.key = entry.getKey();
- this.value = entry.getValue();
- }
- public MapEntry(String key, Object value) {
- super();
- this.key = key;
- this.value = value;
- }
- public String getKey() {
- return key;
- }
- public void setKey(String key) {
- this.key = key;
- }
- public Object getValue() {
- return value;
- }
- public void setValue(Object value) {
- this.value = value;
- }
- }
- }
3. 下面是WebService接口类,注意其中的@XmlJavaTypeAdapter注解部分
- package com.googlecode.garbagecan.cxfstudy.type.sample2;
- import java.util.List;
- import java.util.Map;
- import javax.jws.WebMethod;
- import javax.jws.WebResult;
- import javax.jws.WebService;
- import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
- @WebService
- public interface UserService {
- @WebMethod
- @WebResult List
getUserList(); - @WebMethod
- @XmlJavaTypeAdapter(MapAdapter.class)
- @WebResult Map
getUserMap(); - }
4. WebService接口实现类
- package com.googlecode.garbagecan.cxfstudy.type.sample2;
- import java.util.ArrayList;
- import java.util.LinkedHashMap;
- import java.util.List;
- import java.util.Map;
- public class UserServiceImpl implements UserService {
- public List
getUserList() { - List
userList = new ArrayList (); - for (int i = 0; i < 10; i++) {
- User user = new User();
- user.setId("" + i);
- user.setName("user_" + i);
- user.setPassword("password_" + i);
- userList.add(user);
- }
- return userList;
- }
- public Map
getUserMap() { - Map
userMap = new LinkedHashMap (); - for (int i = 0; i < 10; i++) {
- User user = new User();
- user.setId("" + i);
- user.setName("user_" + i);
- user.setPassword("password_" + i);
- userMap.put(user.getId(), user);
- }
- return userMap;
- }
- }
5. 最后是一个单元测试类
- package com.googlecode.garbagecan.cxfstudy.type.sample2;
- import java.util.List;
- import java.util.Map;
- import javax.xml.ws.Endpoint;
- import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
- import org.junit.After;
- import org.junit.Assert;
- import org.junit.Before;
- import org.junit.BeforeClass;
- import org.junit.Test;
- public class UserServiceTest {
- private static final String address = "http://localhost:9000/ws/type/sample2/userService";
- private UserService userService;
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- Endpoint.publish(address, new UserServiceImpl());
- }
- @Before
- public void setUp() throws Exception {
- JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean();
- factoryBean.setAddress(address);
- factoryBean.setServiceClass(UserService.class);
- Object obj = factoryBean.create();
- userService = (UserService)obj;
- }
- @After
- public void tearDown() throws Exception {
- userService = null;
- }
- @Test
- public void testGetUserList() {
- Assert.assertNotNull(userService);
- List
users = userService.getUserList(); - Assert.assertNotNull(users);
- Assert.assertEquals(10, users.size());
- }
- @Test
- public void testGetUserMap() {
- Assert.assertNotNull(userService);
- Map
users = userService.getUserMap(); - Assert.assertNotNull(users);
- Assert.assertEquals(10, users.size());
- }
- }
6. 运行单元测试类验证上面的实现。