大湖之子 发表于 2017-1-7 07:27:55

Apache CXF实战之三 Map类型绑定

  在CXF中,如果Web Service返回类型是Map的时候,比如方法签名如下
view plaincopyprint?



[*]@WebMethod  
[*]@WebResult Map<String, User> getUserMap();  

  此时如果运行程序会得到类似下面的异常
view plaincopyprint?



[*]...  
[*]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  
[*]...  

  如果把方法签名改为如下时
view plaincopyprint?



[*]@WebMethod  
[*]@WebResult HashMap<String, User> getUserMap();  

  运行程序会发现返回的结果总是一个空的HashMap。
  对于以上问题,此时需要对Map类型做一下数据绑定或者说转换,看下面详细例子
  1. 首先是一个实体类
view plaincopyprint?



[*]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类型做转换的类和适配器类
view plaincopyprint?



[*]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注解部分
view plaincopyprint?



[*]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接口实现类
view plaincopyprint?



[*]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. 最后是一个单元测试类
view plaincopyprint?



[*]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. 运行单元测试类验证上面的实现。
页: [1]
查看完整版本: Apache CXF实战之三 Map类型绑定