Apache CXF实战之八 Map类型绑定

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

  1. @WebMethod 
  2. @WebResult Map<String, User> getUserMap(); 
    @WebMethod
    @WebResult Map<String, User> getUserMap();
此时如果运行程序会得到类似下面的异常
  1. ... 
  2. Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions 
  3. java.util.Map is an interface, and JAXB can't handle interfaces. 
  4.     this problem is related to the following location: 
  5.         at java.util.Map 
  6.         at private java.util.Map com.googlecode.garbagecan.cxfstudy.type.sample2.jaxws_asm.GetUserMapResponse._return 
  7.         at com.googlecode.garbagecan.cxfstudy.type.sample2.jaxws_asm.GetUserMapResponse 
  8. java.util.Map does not have a no-arg default constructor. 
  9.     this problem is related to the following location: 
  10.         at java.util.Map 
  11.         at private java.util.Map com.googlecode.garbagecan.cxfstudy.type.sample2.jaxws_asm.GetUserMapResponse._return 
  12.         at com.googlecode.garbagecan.cxfstudy.type.sample2.jaxws_asm.GetUserMapResponse 
  13.     at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:102
  14.     at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:472
  15.     at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:302
  16.     at com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1136
  17.     at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:154
  18.     at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:121
  19.     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
  20.     at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 
  21.     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
  22.     at java.lang.reflect.Method.invoke(Unknown Source) 
  23.     at javax.xml.bind.ContextFinder.newInstance(Unknown Source) 
  24.     at javax.xml.bind.ContextFinder.newInstance(Unknown Source) 
  25.     at javax.xml.bind.ContextFinder.find(Unknown Source) 
  26.     at javax.xml.bind.JAXBContext.newInstance(Unknown Source) 
  27.     at org.apache.cxf.jaxb.JAXBDataBinding.createContext(JAXBDataBinding.java:560
  28.     at org.apache.cxf.jaxb.JAXBDataBinding.createJAXBContextAndSchemas(JAXBDataBinding.java:500
  29.     at org.apache.cxf.jaxb.JAXBDataBinding.initialize(JAXBDataBinding.java:320
  30.     ... 25 more 
  31. ... 
...
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
...
如果把方法签名改为如下时

  1. @WebMethod 
  2. @WebResult HashMap<String, User> getUserMap(); 
    @WebMethod
    @WebResult HashMap<String, User> getUserMap();
运行程序会发现返回的结果总是一个空的HashMap。


对于以上问题,此时需要对Map类型做一下数据绑定或者说转换,看下面详细例子

1. 首先是一个实体类

  1. package com.googlecode.garbagecan.cxfstudy.type.sample2; 
  2.  
  3. public class User { 
  4.     private String id; 
  5.     private String name; 
  6.     private String password; 
  7.     public String getId() { 
  8.         return id; 
  9.     } 
  10.     public void setId(String id) { 
  11.         this.id = id; 
  12.     } 
  13.     public String getName() { 
  14.         return name; 
  15.     } 
  16.     public void setName(String name) { 
  17.         this.name = name; 
  18.     } 
  19.     public String getPassword() { 
  20.         return password; 
  21.     } 
  22.     public void setPassword(String password) { 
  23.         this.password = password; 
  24.     } 
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类型做转换的类和适配器类

  1. package com.googlecode.garbagecan.cxfstudy.type.sample2; 
  2.  
  3. import java.util.HashMap; 
  4. import java.util.Map; 
  5.  
  6. import javax.xml.bind.annotation.adapters.XmlAdapter; 
  7.  
  8. public class MapAdapter extends XmlAdapter<MapConvertor, Map<String, Object>> { 
  9.  
  10.     @Override 
  11.     public MapConvertor marshal(Map<String, Object> map) throws Exception { 
  12.         MapConvertor convertor = new MapConvertor(); 
  13.         for (Map.Entry<String, Object> entry : map.entrySet()) { 
  14.             MapConvertor.MapEntry e = new MapConvertor.MapEntry(entry); 
  15.             convertor.addEntry(e); 
  16.         } 
  17.         return convertor; 
  18.     } 
  19.  
  20.     @Override 
  21.     public Map<String, Object> unmarshal(MapConvertor map) throws Exception { 
  22.         Map<String, Object> result = new HashMap<String, Object>(); 
  23.         for (MapConvertor.MapEntry e : map.getEntries()) { 
  24.             result.put(e.getKey(), e.getValue()); 
  25.         } 
  26.         return result; 
  27.     } 
  28.  
  29. package com.googlecode.garbagecan.cxfstudy.type.sample2; 
  30.  
  31. import java.util.ArrayList; 
  32. import java.util.List; 
  33. import java.util.Map; 
  34.  
  35. import javax.xml.bind.annotation.XmlAccessType; 
  36. import javax.xml.bind.annotation.XmlAccessorType; 
  37. import javax.xml.bind.annotation.XmlType; 
  38.  
  39. @XmlType(name = "MapConvertor"
  40. @XmlAccessorType(XmlAccessType.FIELD) 
  41. public class MapConvertor { 
  42.     private List<MapEntry> entries = new ArrayList<MapEntry>(); 
  43.  
  44.     public void addEntry(MapEntry entry) { 
  45.         entries.add(entry); 
  46.     } 
  47.  
  48.     public List<MapEntry> getEntries() { 
  49.         return entries; 
  50.     } 
  51.      
  52.     public static class MapEntry { 
  53.  
  54.         private String key; 
  55.  
  56.         private Object value; 
  57.          
  58.         public MapEntry() { 
  59.             super(); 
  60.         } 
  61.  
  62.         public MapEntry(Map.Entry<String, Object> entry) { 
  63.             super(); 
  64.             this.key = entry.getKey(); 
  65.             this.value = entry.getValue(); 
  66.         } 
  67.  
  68.         public MapEntry(String key, Object value) { 
  69.             super(); 
  70.             this.key = key; 
  71.             this.value = value; 
  72.         } 
  73.  
  74.         public String getKey() { 
  75.             return key; 
  76.         } 
  77.  
  78.         public void setKey(String key) { 
  79.             this.key = key; 
  80.         } 
  81.  
  82.         public Object getValue() { 
  83.             return value; 
  84.         } 
  85.  
  86.         public void setValue(Object value) { 
  87.             this.value = value; 
  88.         } 
  89.     } 
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注解部分

  1. package com.googlecode.garbagecan.cxfstudy.type.sample2; 
  2.  
  3. import java.util.List; 
  4. import java.util.Map; 
  5.  
  6. import javax.jws.WebMethod; 
  7. import javax.jws.WebResult; 
  8. import javax.jws.WebService; 
  9. import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 
  10.  
  11. @WebService 
  12. public interface UserService { 
  13.  
  14.     @WebMethod 
  15.     @WebResult List<User> getUserList(); 
  16.  
  17.     @WebMethod 
  18.     @XmlJavaTypeAdapter(MapAdapter.class
  19.     @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接口实现类

  1. package com.googlecode.garbagecan.cxfstudy.type.sample2; 
  2.  
  3. import java.util.ArrayList; 
  4. import java.util.LinkedHashMap; 
  5. import java.util.List; 
  6. import java.util.Map; 
  7.  
  8. public class UserServiceImpl implements UserService { 
  9.  
  10.     public List<User> getUserList() { 
  11.         List<User> userList = new ArrayList<User>(); 
  12.         for (int i = 0; i < 10; i++) { 
  13.             User user = new User(); 
  14.             user.setId("" + i); 
  15.             user.setName("user_" + i); 
  16.             user.setPassword("password_" + i); 
  17.             userList.add(user); 
  18.         } 
  19.         return userList; 
  20.     } 
  21.  
  22.     public Map<String, User> getUserMap() { 
  23.         Map<String, User> userMap = new LinkedHashMap<String, User>(); 
  24.         for (int i = 0; i < 10; i++) { 
  25.             User user = new User(); 
  26.             user.setId("" + i); 
  27.             user.setName("user_" + i); 
  28.             user.setPassword("password_" + i); 
  29.             userMap.put(user.getId(), user); 
  30.         } 
  31.         return userMap; 
  32.     } 
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. 最后是一个单元测试类

  1. package com.googlecode.garbagecan.cxfstudy.type.sample2; 
  2.  
  3. import java.util.List; 
  4. import java.util.Map; 
  5.  
  6. import javax.xml.ws.Endpoint; 
  7.  
  8. import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; 
  9. import org.junit.After; 
  10. import org.junit.Assert; 
  11. import org.junit.Before; 
  12. import org.junit.BeforeClass; 
  13. import org.junit.Test; 
  14.  
  15. public class UserServiceTest { 
  16.  
  17.     private static final String address = "http://localhost:9000/ws/type/sample2/userService"
  18.      
  19.     private UserService userService; 
  20.      
  21.     @BeforeClass 
  22.     public static void setUpBeforeClass() throws Exception { 
  23.         Endpoint.publish(address, new UserServiceImpl()); 
  24.     } 
  25.      
  26.     @Before 
  27.     public void setUp() throws Exception { 
  28.         JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean(); 
  29.         factoryBean.setAddress(address); 
  30.         factoryBean.setServiceClass(UserService.class); 
  31.         Object obj = factoryBean.create(); 
  32.         userService = (UserService)obj; 
  33.     } 
  34.  
  35.     @After 
  36.     public void tearDown() throws Exception { 
  37.         userService = null
  38.     } 
  39.  
  40.     @Test 
  41.     public void testGetUserList() { 
  42.         Assert.assertNotNull(userService); 
  43.         List<User> users = userService.getUserList(); 
  44.         Assert.assertNotNull(users); 
  45.         Assert.assertEquals(10, users.size()); 
  46.     } 
  47.  
  48.     @Test 
  49.     public void testGetUserMap() { 
  50.         Assert.assertNotNull(userService); 
  51.         Map<String, User> users = userService.getUserMap(); 
  52.         Assert.assertNotNull(users); 
  53.         Assert.assertEquals(10, users.size()); 
  54.     } 
  55.  
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. 运行单元测试类验证上面的实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值