本文链接:http://blog.csdn.net/kongxx/article/details/7544640
在CXF中,如果Web Service返回类型是Map的时候,比如方法签名如下
[java] view plain copy print ?
- @WebMethod
- @WebResult Map<String, User> getUserMap();
@WebMethod
@WebResult Map<String, User> getUserMap();
此时如果运行程序会得到类似下面的异常
[java] view plain copy print ?
- ...
- 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.<init>(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
- ...
...
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.<init>(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
...
如果把方法签名改为如下时
[java] view plain copy print ?
- @WebMethod
- @WebResult HashMap<String, User> getUserMap();
@WebMethod
@WebResult HashMap<String, User> getUserMap();
运行程序会发现返回的结果总是一个空的HashMap。
对于以上问题,此时需要对Map类型做一下数据绑定或者说转换,看下面详细例子
1. 首先是一个实体类
[java] view plain copy print ?
- 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;
- }
- }
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类型做转换的类和适配器类
[java] view plain copy print ?
- 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<MapConvertor, Map<String, Object>> {
-
- @Override
- public MapConvertor marshal(Map<String, Object> map) throws Exception {
- MapConvertor convertor = new MapConvertor();
- for (Map.Entry<String, Object> entry : map.entrySet()) {
- MapConvertor.MapEntry e = new MapConvertor.MapEntry(entry);
- convertor.addEntry(e);
- }
- return convertor;
- }
-
- @Override
- public Map<String, Object> unmarshal(MapConvertor map) throws Exception {
- Map<String, Object> result = new HashMap<String, Object>();
- 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<MapEntry> entries = new ArrayList<MapEntry>();
-
- public void addEntry(MapEntry entry) {
- entries.add(entry);
- }
-
- public List<MapEntry> getEntries() {
- return entries;
- }
-
- public static class MapEntry {
-
- private String key;
-
- private Object value;
-
- public MapEntry() {
- super();
- }
-
- public MapEntry(Map.Entry<String, Object> 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;
- }
- }
- }
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<MapConvertor, Map<String, Object>> {
@Override
public MapConvertor marshal(Map<String, Object> map) throws Exception {
MapConvertor convertor = new MapConvertor();
for (Map.Entry<String, Object> entry : map.entrySet()) {
MapConvertor.MapEntry e = new MapConvertor.MapEntry(entry);
convertor.addEntry(e);
}
return convertor;
}
@Override
public Map<String, Object> unmarshal(MapConvertor map) throws Exception {
Map<String, Object> result = new HashMap<String, Object>();
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<MapEntry> entries = new ArrayList<MapEntry>();
public void addEntry(MapEntry entry) {
entries.add(entry);
}
public List<MapEntry> getEntries() {
return entries;
}
public static class MapEntry {
private String key;
private Object value;
public MapEntry() {
super();
}
public MapEntry(Map.Entry<String, Object> 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注解部分
[java] view plain copy print ?
- 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<User> getUserList();
-
- @WebMethod
- @XmlJavaTypeAdapter(MapAdapter.class)
- @WebResult Map<String, User> getUserMap();
- }
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<User> getUserList();
@WebMethod
@XmlJavaTypeAdapter(MapAdapter.class)
@WebResult Map<String, User> getUserMap();
}
4. WebService接口实现类
[java] view plain copy print ?
- 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<User> getUserList() {
- List<User> userList = new ArrayList<User>();
- 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<String, User> getUserMap() {
- Map<String, User> userMap = new LinkedHashMap<String, User>();
- 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;
- }
- }
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<User> getUserList() {
List<User> userList = new ArrayList<User>();
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<String, User> getUserMap() {
Map<String, User> userMap = new LinkedHashMap<String, User>();
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. 最后是一个单元测试类
[java] view plain copy print ?
- 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<User> users = userService.getUserList();
- Assert.assertNotNull(users);
- Assert.assertEquals(10, users.size());
- }
-
- @Test
- public void testGetUserMap() {
- Assert.assertNotNull(userService);
- Map<String, User> users = userService.getUserMap();
- Assert.assertNotNull(users);
- Assert.assertEquals(10, users.size());
- }
-
- }
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<User> users = userService.getUserList();
Assert.assertNotNull(users);
Assert.assertEquals(10, users.size());
}
@Test
public void testGetUserMap() {
Assert.assertNotNull(userService);
Map<String, User> users = userService.getUserMap();
Assert.assertNotNull(users);
Assert.assertEquals(10, users.size());
}
}
6. 运行单元测试类验证上面的实现。