• CXF传输复杂对象问题


    这两天在做使用CXF框架的时候遇到了一个传输复杂对象的问题,问题如下:

    背景:
    首先,我定义一个JavaBean WebServiceResult 里面有这么几个属性:
    private boolean success =false;
    private Map<String,List<Topic>> result = new HashMap<String,List<Topic>>();
    private ArrayList<Topic> topics ;
    private transient String resultCode;
    其中,Map我暂且叫做“复杂对象” 因为 一个map里面,装了一个list,而list里面又装了一个自己的JavaBean Topic(活动信息)
    接口调用完成后会用WebServiceResult 封装调用结果返回给客户端
    用客户端调用该接口后发现,result属性值为null,但是,对服务端的debug排除了没有set值的情况,查看后还发现了服务端抛出了
    "class XXX nor any of its super class is known to this context" 的异常
    排查过程:
    1. 从异常内容可以看到CXF内部应该有至少一个上下文环境存放当前接口涉及到的Java类的class信息
    2. 通过异常定位到CXF内部,debug后理解上下文环境,可以看到,异常出自这里:

    fatal在调用的时候就写死了为true,当bi为null时,就会报出异常,再看getBeanInfon内部:

    o对象既是需要将数据绑定到xml文件上的对象,在这里是o是接口调用后返回的对象
    比如:接口方法签名为:

    那这里的o可能是WebServiceResult,和WebServiceResult内部的各个实例变量(是"循环遍历"WebServiceResult内的所有对象,调用getBeanInfo方法)
    回到getBeanInfon方法,程序会从beanInfoMap中取出预置好的将Bean映射到xml上的对象JaxBean(这里先卖个弯子,后面会说到它怎么来的)
    如果beanInfoMap里没有这个class对应的JaxBeanInfo对象,就会return一个null,导致了异常的报出。
    几个疑问:
    1. JaxBeanInfo是做什么的?
    JaxBeanInfo里封装了对大部分Java类映射方式,即,怎么把数据映射到XML上主要方法有:

    主要子类有:

    2. beanInfoMap是做什么的?
    我的理解是:在服务端初始化的时候,CXF会去看这个接口里,参数和返回值的类型,并根据类型生成相应的JaxBeanInfo对象放在map里面,
    这里好理解,就是等接口被调用时知道 "怎么" 把返回值 映射到XML上,传给客户端。
    3. 既然是在服务端初始化的时候去遍历方法签名,将涉及的Bean的相对应的解析对象放到Map中,又怎么会在接口返回的时候找不到解析该Bean的JaxBean呢?
    回到这段代码:

    再看他的上层调用:

    问题就在这里,如WebServiceResult 中的声明:private Map<String,List<Topic>> result = new HashMap<String,List<Topic>>();
    CXF在初始化的时候,“登记”的是List,保存的class信息为java.util.List 而我们在时间使用的时候,通常是这样,
    List<Topic> topics = new ArrayList<Topic>() 这个时候,topics的class信息是:java.util.ArrayList
    当接口调用返回的时候,上图中的 : boolean asExpected = chlid.getCalss() == expected.jaxbType;
    就是那 java.util.List == java.util.ArrayList 导致比较失败,最终进入grammar.getBeanInfo去拿jaxBeanInfo的时候,
    因为”登记“的是java.util.List的JaxBeanInfo而不是java.util.ArrayList,导致拿不到jaxBeanInfo,最后报出异常。
    解决方法
    解决方法非常简单,当我们在声明接口参数和返回值的时候,别使用到接口或者抽象类 比如java.util.List等
    而是直接写成他们的实现类或者子类 保证实际调用方法的时候的class信息和方法声明的class信息是一致的就可以了,因此,WebServiceResult 改为如下后,可以正常传输
    private boolean success =false;
    private Map<String,ArrayList<Topic>> result = new HashMap<String,ArrayList<Topic>>();
    private ArrayList<Topic> topics ;
    private transient String resultCode;
    ps: 网上有说CXF不支持Map等复杂对象的传输,经过测试,在Jaxb 2.1(CXF 2.2 版本依赖)版本是不存在该问题的。
    未解决的问题:
    1. Map<String,ArrayList<Topic>> 格式的result传输不会报错,但是map中的list的值会"丢失",即,客户端收到的是空的List(单独一个List传输是不会的)。
    遗留下来的问题,有空再解决下,大家有知道的也请楼下回复
  • 相关阅读:
    [SQL] 外卖系统数据库设计
    [PHP] 遗传算法求函数最大值一般实现
    PHP CURL根据详细地址获取腾讯地图经纬度
    PHP 递归读取无限级分类
    PHP 仿网易云的评论盖楼
    JavaScript清除空格、换行,把双引号转换成单引号
    百度地图小Demo---获取当前地址以及拖拽显示地址
    基于Modbus的C#串口调试开发
    二叉树的中序遍历
    二叉树的前序遍历
  • 原文地址:https://www.cnblogs.com/bjanzhuo/p/3576078.html
Copyright © 2020-2023  润新知