1. 云栖社区>
  2. PHP教程>
  3. 正文

通过webservice调用一对多自关联时的循环引用问题

作者:用户 来源:互联网 时间:2017-12-01 14:56:34

引用问题webservice循环调用关联通过

通过webservice调用一对多自关联时的循环引用问题 - 摘要: 本文讲的是通过webservice调用一对多自关联时的循环引用问题, 实体类如下: public class ResourceCategory implements Serializable {    private static final long serialVersionUID = 1L;     


实体类如下:


public class ResourceCategory implements Serializable {
    private static final long serialVersionUID = 1L;
   
    // 主键
    private Integer id;
   
    // 名称
    private String name_;
   
    ............................



    // 外键,上级分类唯一标识符
   
    private ResourceCategory parent;
   
    // 子资源类别
    private List children = new ArrayList(); 
}


 


主要的异常信息如下:


javax.xml.soap.SOAPException: javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.SAXException2: A cycle is detected in the object graph.
This will cause infinitely deep XML: Mogno -> Door-> Mogno]
java.lang.RuntimeException: javax.xml.soap.SOAPException:
javax.xml.soap.SOAPException : javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.SAXException2: A cycle is detected in the object graph.
This will cause infinitely deep XML: Mogno -> Door-> Mogno]


 


循环引用:
Parent 和 Child是1:n的关系, Parent含有一个child的列表children,child对于parent有一个引用,那这两个对象之间就存在循环引用的关系.


 


我们不能
直接将带有环的对象暴露给webservice,因为这会导致最终生成xml的时候会陷入死循环最后栈溢出,所以cxf检测出对象存在cycle会抛出一
个异常阻止进一步发布webservice.(以前的XFire可没这么聪明,它没有检测机制,直接就去序列化xml结果会导致
OutOfMemory).


 


如何解决呢?就是要破掉这个环,去某一端,如何在不破坏原有设计的情况下做到这一点,[email protected]
这个annotation会标明这个字段不要解析成xml,所有你不想解析进webservice的都可以通过这个标签来标记
注:cxf默认采用JAXB做databindings,如果要用aegis,[email protected]
像这种情况,我们一般要打破子对父的引用,就是要打破Child对于Parent的引用.注意要在parent的get方法上面加而不是在parent的声明处.
这样从生成的wsdl里面我们就看不到child里有对于parent的引用


 


虽然client能够拿到children列表了,但通过child得不到parent的信息,因为在client现在是单向的,那我也想访问parent怎么办?
这里有一个解决办法,在Parent下面加入如下代码:
    public void afterUnmarshal(Unmarshaller u, Object parent) {
        this.parent = (Parent) parent;
    }
怎么做到的?背后的道理是这样的:
循环的双向关系,一端到另一端的关系确定了以后,反过来另一端也就确定了.
cxf在解析wsdl映射成对象的过程中(也就是unmarshal),处理Parent并处理它所包含的child,结果发现parent引
用的child有afterUnmarshal方法,然后把自己的引用通过该方法传递给child,这样child也具有了对于
parent的引用,这一切都是在客户端完成的.真的是很聪明的做法.
这些功能必须要cxf来做客户端才能实现,但我们可以利用这种技术来在其他客户端实现这个功能.比如flex,.net, php 等等.


one more thing


上面的例子首先访问的是parent,cxf可以拿到两端的信息,但如果先访问child就拿不到parent了.
[email protected], 同样道理, child可以得到parent的信息,但是这个parent的getChildren里恐怕就只有那一个child了.
所以还是看具体设计,如果parent需要经常访问child,第一种最好,如果child要经常访问parent,显然是第二种


 

以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索引用 , 问题 , webservice , 循环 , 调用 , 关联 , 通过 ,以便于您获取更多的相关知识。