今天遇到一个通过cxf框架实现webservice调用的问题,百度等搜索以后没找到解决问题的方法,所以将解决方法分享出来,希望对大家有所帮助。
1.现象描述:
通过webservice方式执行方法WfPackage getPackage(String pkgId)时,在方法返回时抛出异常。
2014-04-08 14:33:00,244: EXCEPTION
java.lang.*Error
at java.nio.ByteOrder.nativeOrder(ByteOrder.java:56)
at java.nio.DirectByteBuffer.put(DirectByteBuffer.java:313)
at org.mortbay.io.nio.DirectNIOBuffer.poke(DirectNIOBuffer.java:201)
at org.mortbay.io.nio.DirectNIOBuffer.poke(DirectNIOBuffer.java:141)
at org.mortbay.io.AbstractBuffer.put(AbstractBuffer.java:448)
at org.mortbay.jetty.HttpGenerator.addContent(HttpGenerator.java:148)
at org.mortbay.jetty.AbstractGenerator$Output.write(AbstractGenerator.java:644)
at org.mortbay.jetty.AbstractGenerator$Output.write(AbstractGenerator.java:579)
at org.apache.cxf.io.AbstractWrappedOutputStream.write(AbstractWrappedOutputStream.java:46)
at com.ctc.wstx.io.UTF8Writer.flush(UTF8Writer.java:96)
at com.ctc.wstx.sw.BufferingXmlWriter.flush(BufferingXmlWriter.java:184)
at com.ctc.wstx.sw.BaseStreamWriter.flush(BaseStreamWriter.java:311)
at org.apache.cxf.aegis.xml.stax.ElementWriter.close(ElementWriter.java:165)
at org.apache.cxf.aegis.type.basic.BeanType.writeElement(BeanType.java:398)
at org.apache.cxf.aegis.type.basic.BeanType.writeObjectInternal(BeanType.java:380)
at org.apache.cxf.aegis.type.basic.BeanType.writeObject(BeanType.java:320)
at org.apache.cxf.aegis.type.basic.BeanType.writeElement(BeanType.java:396)
at org.apache.cxf.aegis.type.basic.BeanType.writeObjectInternal(BeanType.java:380)
at org.apache.cxf.aegis.type.basic.BeanType.writeObject(BeanType.java:320)
at org.apache.cxf.aegis.type.basic.BeanType.writeElement(BeanType.java:396)
at org.apache.cxf.aegis.type.basic.BeanType.writeObjectInternal(BeanType.java:380)
at org.apache.cxf.aegis.type.basic.BeanType.writeObject(BeanType.java:320)
//----xxx此处省略n行----------------
2014-4-8 14:33:01 org.apache.cxf.phase.PhaseInterceptorChain doIntercept
信息: Interceptor has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Can't overwrite cause
at org.apache.cxf.aegis.databinding.XMLStreamDataReader.read(XMLStreamDataReader.java:62)
at org.apache.cxf.aegis.databinding.XMLStreamDataReader.read(XMLStreamDataReader.java:38)
at org.apache.cxf.interceptor.DocLiteralInInterceptor.getPara(DocLiteralInInterceptor.java:235)
at org.apache.cxf.interceptor.DocLiteralInInterceptor.handleMessage(DocLiteralInInterceptor.java:120)
//----xxx此处省略n行----------------
Caused by: java.lang.IllegalStateException: Can't overwrite cause
at java.lang.Throwable.initCause(Throwable.java:320)
at com.ctc.wstx.compat.Jdk14Impl.setInitCause(Jdk14Impl.java:70)
at com.ctc.wstx.exc.WstxException.<init>(WstxException.java:46)
at com.ctc.wstx.exc.WstxIOException.<init>(WstxIOException.java:16)
at com.ctc.wstx.sr.StreamScanner.throwFromIOE(StreamScanner.java:683)
at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1086)
at org.apache.cxf.staxutils.DepthXMLStreamReader.next(DepthXMLStreamReader.java:220)
at org.apache.cxf.aegis.xml.stax.ElementReader.getValue(ElementReader.java:136)
at org.apache.cxf.aegis.type.basic.StringType.readObject(StringType.java:36)
at org.apache.cxf.aegis.type.basic.BeanType.readObject(BeanType.java:161)
at org.apache.cxf.aegis.type.basic.BeanType.readObject(BeanType.java:161)
at org.apache.cxf.aegis.type.basic.ArrayType.readCollection(ArrayType.java:86)
at org.apache.cxf.aegis.type.collection.CollectionType.readObject(CollectionType.java:52)
at org.apache.cxf.aegis.type.basic.BeanType.readObject(BeanType.java:161)
at org.apache.cxf.aegis.type.basic.BeanType.readObject(BeanType.java:161)
at org.apache.cxf.aegis.type.basic.ArrayType.readCollection(ArrayType.java:86)
at org.apache.cxf.aegis.type.collection.CollectionType.readObject(CollectionType.java:52)
at org.apache.cxf.aegis.type.basic.BeanType.readObject(BeanType.java:161)
at org.apache.cxf.aegis.type.basic.BeanType.readObject(BeanType.java:161)
at org.apache.cxf.aegis.type.basic.ArrayType.readCollection(ArrayType.java:86)
at
//----xxx此处省略n行----------------
2.分析:
从异常看,是因为方法栈调用陷入了死循环,导致栈内存溢出,应该服务器端执行完,WfPackage接口的实例通过aegis序列化成xml时导致了死循环。
下面看一下WfPackage代码片段:
WfProcessDefinition代码片段:
WfActivityDefinition代码片段:
WfTransition代码片段:
其中类WfPackage依赖了WfProcessDefinition, 类WfProcessDefinition依赖了WfActivityDefinition,
对象WfActivityDefinition依赖了WfTransition,WfTransition又依赖了WfActivityDefinition,存在循环依赖。
初步怀疑是这个问题导致的。
将WfTransition中的
/**
* 目标活动
*/
public WfActivityDefinition getToActivity();
/**
* 源活动
*/
public WfActivityDefinition getFromActivity();
改为:
/**
* 目标活动
*/
public String getToActDefId();
/**
* 源活动
*/
public String getFromActDefId();
返回活动定义的Id
去掉了WfTransition中对WfActivityDefinition的依赖。
去掉后,问题解决,测试通过。
3.其他:
看来aegis数据绑定,除了下面几个约束外,还不允许类的循环依赖。
1.入参、出参如果是集合类型,必须使用泛型,集合中的对象类型的属性、方法中如果有集合类型,也必须使用泛型标识出具体的类型,这个一直到递归到底。
2.必须有setter和getter方法,有setter和getter方法的话,必须有这个属性。