急!!CXF返回类型为List<Map>的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了急!!CXF返回类型为List<Map>的问题相关的知识,希望对你有一定的参考价值。

#service:
@WebMethod
@XmlJavaTypeAdapter(MapInListAdapter.class)
public List<Map<String,String>> getMember();
#adapter:
public class MapInListAdapter extends XmlAdapter<MapInListConvertor,List<Map>>

@Override
public MapInListConvertor marshal(List<Map> list) throws Exception
System.out.println("marshaling..");
MapInListConvertor convertor = new MapInListConvertor();
for(Map<Object,Object> map : list)
MapConvertor mc = new MapConvertor();
for(Entry<Object,Object> entry : map.entrySet())
mc.addEntry(new MapEntry(entry));

convertor.addMapConvertor(mc);

return convertor;


@Override
public List<Map> unmarshal(MapInListConvertor convertor) throws Exception
System.out.println("unmarshaling..");
List<Map> list = new ArrayList();
for(MapConvertor mc : convertor.getMapConvertorList())
Map map = new HashMap();
for(MapEntry entry : mc.getEntries())
map.put(entry.getKey(), entry.getValue());

list.add(map);

return list;



convertor:
@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 void setEntries(List<MapEntry> entries)
this.entries = entries;


public static class MapEntry

private Object key;

private Object value;

public MapEntry()

public MapEntry(Map.Entry<Object,Object> entry)
this.key = entry.getKey();
this.value = entry.getValue();


public MapEntry(Object key , Object value)
this.key = key;
this.value = value;


public Object getKey()
return key;


public void setKey(Object key)
this.key = key;


public Object getValue()
return value;


public void setValue(Object value)
this.value = value;




客户端运行的时候确报:
javax.xml.ws.soap.SOAPFaultException: java.util.ArrayList cannot be cast to java.util.Map
小弟经验尚浅,希望各位大哥们给点指示

参考技术A 遇到同样的问题!一年了,竟没个人出来指点。。。 参考技术B 3年了,还是没人解决吗 参考技术C 三年半了,居然还没人回答。。 参考技术D 哎~~7年之痒啊,结案了~还是没有答案啊。WebService是不是该淘汰了。 第5个回答  2016-06-27 五年半了,居然还没有人来解决,哎!

cxf处理java bean及ListMap类型

      项目中经常是处理复合类型比如集合List、Map,下面就cxf处理复合类型进行讲解。

具体例子如下:

   这里实例是客户端传一个JavaBean,服务器端返回集合类型;

 一、  接口返回List处理:

    在原来的项目实例(cxf开发webService服务端口)基础上,我们先创建一个实体类User:

 1 /**
 2  * 
 3  */
 4 package com.hik.entity;
 5 
 6 /**
 7  * @ClassName: User
 8  * @Description: 用户实体类
 9  * @author jed
10  * @date 2017年7月30日下午2:44:41
11  *
12  */
13 public class User {
14 
15     private Integer id; // 编号
16     private String userName; //用户名
17     private String password; //密码
18     
19     public Integer getId() {
20         return id;
21     }
22     public void setId(Integer id) {
23         this.id = id;
24     }
25     public String getUserName() {
26         return userName;
27     }
28     public void setUserName(String userName) {
29         this.userName = userName;
30     }
31     public String getPassword() {
32         return password;
33     }
34     public void setPassword(String password) {
35         this.password = password;
36     }
37     
38     
39 }
View Code

再创建一个Role实体类:

 1 /**
 2  * 
 3  */
 4 package com.hik.entity;
 5 
 6 /**
 7  * @ClassName: Role
 8  * @Description: TODO
 9  * @author jed
10  * @date 2017年7月30日下午2:46:45
11  *
12  */
13 public class Role {
14 
15     private Integer id; //编号
16     private String roleName; //角色名称
17     
18     public Role() {
19         super();
20     }
21 
22     public Role(Integer id, String roleName) {
23         super();
24         this.id = id;
25         this.roleName = roleName;
26     }
27     
28     public Integer getId() {
29         return id;
30     }
31     public void setId(Integer id) {
32         this.id = id;
33     }
34     public String getRoleName() {
35         return roleName;
36     }
37     public void setRoleName(String roleName) {
38         this.roleName = roleName;
39     }
40     
41     
42 }
View Code

然后HelloWorld再加一个接口方法getRoleByUser,通过用户查找角色:

 1 /**
 2  * 
 3  */
 4 package com.hik.webservice;
 5 
 6 import java.util.List;
 7 
 8 import javax.jws.WebService;
 9 
10 import com.hik.entity.Role;
11 import com.hik.entity.User;
12 
13 /**
14  * @ClassName: HelloWorld
15  * @Description: TODO
16  * @author jed
17  * @date 2017年7月30日上午10:20:35
18  *
19  */
20 @WebService
21 public interface HelloWorld {
22 
23     public String say(String str);
24     
25     public List<Role> getRoleByUser(User user);
26 }
View Code

然后HelloWorld接口实现类 HelloWorldImpl写下新增的方法的具体实现,我们这里写死,模拟下即可:

 1 /**
 2  * 
 3  */
 4 package com.hik.webservice.impl;
 5 
 6 import java.util.ArrayList;
 7 import java.util.List;
 8 
 9 import javax.jws.WebService;
10 
11 import com.hik.entity.Role;
12 import com.hik.entity.User;
13 import com.hik.webservice.HelloWorld;
14 
15 /**
16  * @ClassName: HelloWorldImpl
17  * @Description: TODO
18  * @author jed
19  * @date 2017年7月30日上午10:24:46
20  *
21  */
22 @WebService
23 public class HelloWorldImpl implements HelloWorld{
24 
25     public String say(String str) {
26         return "hello "+str;
27     }
28 
29     public List<Role> getRoleByUser(User user) {
30         List<Role> roleList = new ArrayList<Role>();
31         if(user!=null){
32             if(user.getUserName().equals("jack") && user.getPassword().equals("123456")){
33                 roleList.add(new Role(1, "技术总监"));
34                 roleList.add(new Role(2, "产品经理"));
35             }else if(user.getUserName().equals("lili") && user.getPassword().equals("123456")){
36                 roleList.add(new Role(3, "程序员"));
37             }
38             return roleList;
39         }else{
40             return null;
41         }
42                 
43     }
44 
45 }
View Code

服务端其他地方不用动;再重新发布下webService接口。

下面我们来处理下客户端,和前面讲的一样。我们用wsdl2java工具重新生成代码(参考cxf开发webService客户端及调用服务端的理解 )

 

我们改下Client类:

 1 /**
 2  * 
 3  */
 4 package com.hik.webservice;
 5 
 6 import java.util.List;
 7 
 8 /**
 9  * @ClassName: Client
10  * @Description: TODO
11  * @author jed
12  * @date 2017年7月30日下午1:58:36
13  *
14  */
15 public class Client {
16 
17     public static void main(String[] args) {
18         HelloWorldService service = new HelloWorldService();
19         HelloWorld helloWorld = service.getHelloWorldPort(); //代理
20         //System.out.println(helloWorld.say("你好!"));
21         User user = new User();
22         user.setUserName("lili");
23         user.setPassword("123456"); 
24         List<Role> roleList = helloWorld.getRoleByUser(user);
25         for(Role role : roleList){
26             System.out.println(role.getId()+" , "+role.getRoleName());
27         }
28     }
29 }
View Code

运行截图:

二、接口返回Map处理

      map类型比较特殊,由其数据结构而决定。XmlAdapter类源码也有说明:

 因此,需要写一个适配器来做转换,使用注解annotation注解 。该适配器类需实现抽象类XmlAdapter的两个转换方法。

 

 

 代码例子如下:

  如增加接口:获取所有用用户以及对应的每个用户所有角色信息;

 

服务器端:

HelloWorld接口加方法:

 1 /**
 2      * 
 3      * @MethodName: getRoles
 4      * @Description: 获取所有用户及对应角色
 5      * @author jed
 6      * @date 2017年8月4日下午10:36:59
 7      * @param @return    
 8      * @return Map<String,List<Role>>    返回类型
 9      * @return
10      *
11      */
12     @XmlJavaTypeAdapter(MapAdapter.class)
13     public Map<String, List<Role>> getRoles();
View Code

 

 HelloWorldImpl实现类加方法实现:

 1 public Map<String, List<Role>> getRoles() {
 2         Map<String, List<Role>> map = new HashMap<String, List<Role>>();
 3         List<Role> roleList1 = new ArrayList<Role>();
 4         roleList1.add(new Role(1, "技术总监"));
 5         roleList1.add(new Role(2, "产品经理"));
 6         map.put("admin", roleList1);
 7         List<Role> roleList2 = new ArrayList<Role>();
 8         roleList2.add(new Role(3, "程序员"));
 9         map.put("jack", roleList2);
10         return map;
11     }
View Code

然后我们启动Server类:发现报错:

 报错显示不支持该类型,解决方案,可以使用适配器,把cxf不能接受的类型通过适配器,转能接受的类型。

 

      我们使用@XmlJavaTypeAdapter注解,加在接口定义上,完整接口代码如下:

 

 1 /**
 2  * 
 3  */
 4 package com.hik.webservice;
 5 
 6 import java.util.List;
 7 import java.util.Map;
 8 
 9 import javax.jws.WebService;
10 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
11 
12 import com.hik.adapter.MapAdapter;
13 import com.hik.entity.Role;
14 import com.hik.entity.User;
15 
16 /**
17  * @ClassName: HelloWorld
18  * @Description: TODO
19  * @author jed
20  * @date 2017年7月30日上午10:20:35
21  *
22  */
23 @WebService
24 public interface HelloWorld {
25 
26     public String say(String str);
27     
28     /**
29      * 
30      * @MethodName: getRoleByUser
31      * @Description: 获取用户角色 
32      * @author jed
33      * @date 2017年8月4日下午10:37:30
34      * @param @param user
35      * @param @return    
36      * @return List<Role>    返回类型
37      * @param user
38      * @return
39      *
40      */
41     public List<Role> getRoleByUser(User user);
42     
43     /**
44      * 
45      * @MethodName: getRoles
46      * @Description: 获取所有用户及对应角色
47      * @author jed
48      * @date 2017年8月4日下午10:36:59
49      * @param @return    
50      * @return Map<String,List<Role>>    返回类型
51      * @return
52      *
53      */
54     @XmlJavaTypeAdapter(MapAdapter.class)
55     public Map<String, List<Role>> getRoles();
56 }
View Code

这里参数需要一个实现了XmlAdapter类的适配器类;

这里的话XmlAdapter要加两个参数,XmlAdapter<ValueType,BoundType> 

ValueType是cxf能接收的类型,这里我用了数组;

BoundType是cxf不能接受的类型,也就是我例子里的需求的Map类型;

 1 /**
 2  * 
 3  */
 4 package com.hik.adapter;
 5 
 6 import java.util.HashMap;
 7 import java.util.List;
 8 import java.util.Map;
 9 
10 import javax.xml.bind.annotation.adapters.XmlAdapter;
11 
12 import com.hik.entity.Role;
13 
14 /**
15  * @ClassName: MapAdapter
16  * @Description: Map适配器
17  * @author jed
18  * @date 2017年8月4日下午10:56:41
19  *
20  */
21 public class MapAdapter extends XmlAdapter<MyRole[], Map<String, List<Role>>>{
22 
23     /**
24      * 适配转换  MyRole[] -> Map<String, List<Role>>
25      */
26     @Override
27     public Map<String, List<Role>> unmarshal(MyRole[] v) throws Exception {
28         Map<String, List<Role>> map = new HashMap<String, List<Role>>();
29         for(int i=0;i<v.length;i++){
30             MyRole r = v[i];
31             map.put(r.getKey(), r.getValue());
32         }
33         return map;
34     }
35 
36      /**
37      * 适配转换  Map<String, List<Role>> -> MyRole[]
38      */
39     @Override
40     public MyRole[] marshal(Map<String, List<Role>> v) throws Exception {
41         MyRole[] roles = new MyRole[v.size()];
42         int i=0;
43         for(String key : v.keySet()){
44             roles[i] = new MyRole();
45             roles[i].setKey(key);
46             roles[i].setValue(v.get(key));
47             i++;
48         }
49         
50         return roles;
51     }
52 
53 }
View Code

 

还有一个MyRole自定义类型,key:value。我们搞成两个属性,具体实现如下:

 1 /**
 2  * 
 3  */
 4 package com.hik.adapter;
 5 
 6 import java.util.List;
 7 
 8 import com.hik.entity.Role;
 9 
10 /**
11  * @ClassName: MyRole
12  * @Description: 自定义实体 cxf能接受
13  * @author jed
14  * @date 2017年8月4日下午11:01:23
15  *
16  */
17 public class MyRole {
18 
19     private String key;
20     private List<Role> value;
21     
22     public String getKey() {
23         return key;
24     }
25     public void setKey(String key) {
26         this.key = key;
27     }
28     public List<Role> getValue() {
29         return value;
30     }
31     public void setValue(List<Role> value) {
32         this.value = value;
33     }
34     
35     
36 }
View Code

 

OK  好了。我们运行Server类,发布webservice接口:

发布成功。然后就到了webservice客户端,我们用wsdl2java工具生成下最新代码

 

我们修改下Client类:

 1 /**
 2  * 
 3  */
 4 package com.hik.webservice;
 5 
 6 import java.util.List;
 7 
 8 /**
 9  * @ClassName: Client
10  * @Description: TODO
11  * @author jed
12  * @date 2017年7月30日下午1:58:36
13  *
14  */
15 public class Client {
16 
17     public static void main(String[] args) {
18         HelloWorldService service = new HelloWorldService();
19         HelloWorld helloWorld = service.getHelloWorldPort(); //代理
20         //System.out.println(helloWorld.say("你好!"));
21         /*User user = new User();
22         user.setUserName("lili");
23         user.setPassword("123456"); 
24         List<Role> roleList = helloWorld.getRoleByUser(user);
25         for(Role role : roleList){
26             System.out.println(role.getId()+" , "+role.getRoleName());
27         }*/
28         MyRoleArray array = helloWorld.getRoles();
29         List<MyRole> roleList = array.item;
30         for(int i=0;i<roleList.size();i++){
31             MyRole mr = roleList.get(i);
32             System.out.println(mr.key+":");
33             for(Role r: mr.getValue()){
34                 System.out.println(r.getId()+","+r.getRoleName()+" ");
35             }
36             System.out.println();
37         }
38     }
39 }
View Code

运行结果:

 

    总结: webService处理过程如下:

1、webservice服务器端开发webservice接口,然后发布webservice;

2、通过一个Url调用webservice接口,发布的url是 http://192.168.0.102/helloWorld,则我们请求的url就是 http://192.168.0.102/helloWorld?wsdl  

3、请求成功,返回一大串xml标记。这一大串xml即使wsdl。   wsdl (Web Services Description Language) 也就是Web Service描述语言,描述服务器端定义的webservice接口的相关信息。

4、wsdl描述可看到发布的方法。如:wsdl:types就是定义了一些变量,wsdl:message相当于定义方法,wsdl:portType相当与调用与返回。

5、客户端通过这个url请求,获得wsdl规范的xml文档片段信息,需用到SOAP(Simple Object Access Protocol)即简单对象访问协议,我们通过这个协议,来实现客户端,服务器端消息交互,SOAP使用XML消息调用远程方法;

     当然交互的媒介就是xml,具体交互内容根据wsdl文档描述来。

&nb

以上是关于急!!CXF返回类型为List<Map>的问题的主要内容,如果未能解决你的问题,请参考以下文章

CXF webService Map 适配器模式

Web Service学习之六:CXF解决无法处理的数据类型

mybatis 如何返回list<map<string,object>>

学习webservice之cxf:cxf处理map等复杂类型

怎么才知道List对象中存放的对象的类型呀>>>>急

从 Stream 检索快照时,Flutter/Firestore 返回类型 List<Review> 不是“Map<String, dynamic>”类型的子类型