您的位置:首页 > 编程语言 > Java开发

javax.xml.stream.XMLStreamException: Prefix cannot be null

2012-06-21 16:50 239 查看
近日在把程序从jboss移动到jetty服务器时,使用jaxb的地方在Marshal的时候会抛上面的异常,堆栈信息如下:

ERROR [com.cmri.mcss.web.servlet.confmgmt.ConfPicServlet:65] Could not parse the XML stream.

javax.xml.ws.soap.SOAPFaultException: Could not parse the XML stream.

at org.apache.cxf.jaxws.DispatchImpl.mapException(DispatchImpl.java:235)

at org.apache.cxf.jaxws.DispatchImpl.invoke(DispatchImpl.java:264)

at org.apache.cxf.jaxws.DispatchImpl.invoke(DispatchImpl.java:195)

.....(程序调用的地方,省略部分)

Caused by: org.apache.cxf.interceptor.Fault: Could not parse the XML stream.

at org.apache.cxf.databinding.source.XMLStreamDataWriter.write(XMLStreamDataWriter.java:85)

at org.apache.cxf.databinding.source.XMLStreamDataWriter.write(XMLStreamDataWriter.java:49)

at org.apache.cxf.databinding.source.XMLStreamDataWriter.write(XMLStreamDataWriter.java:45)

at org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor.writeParts(AbstractOutDatabindingInterceptor.java:114)

at org.apache.cxf.interceptor.BareOutInterceptor.handleMessage(BareOutInterceptor.java:68)

at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:236)

at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:471)

at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:301)

at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:253)

at org.apache.cxf.endpoint.ClientImpl.invokeWrapped(ClientImpl.java:288)

at org.apache.cxf.jaxws.DispatchImpl.invoke(DispatchImpl.java:257)

... 38 more

Caused by: javax.xml.stream.XMLStreamException: javax.xml.bind.MarshalException

- with linked exception:

[javax.xml.stream.XMLStreamException: Prefix cannot be null]

at org.apache.cxf.staxutils.StaxUtils.copy(StaxUtils.java:339)

at org.apache.cxf.databinding.source.XMLStreamDataWriter.write(XMLStreamDataWriter.java:82)

... 48 more

Caused by: javax.xml.bind.MarshalException

- with linked exception:

[javax.xml.stream.XMLStreamException: Prefix cannot be null]

at javax.xml.bind.util.JAXBSource$1.parse(JAXBSource.java:225)

at javax.xml.bind.util.JAXBSource$1.parse(JAXBSource.java:210)

at org.apache.cxf.staxutils.StaxUtils.copy(StaxUtils.java:335)

... 49 more

Caused by: javax.xml.bind.MarshalException

- with linked exception:

[javax.xml.stream.XMLStreamException: Prefix cannot be null]

at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:328)

at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:254)

at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:103)

at javax.xml.bind.util.JAXBSource$1.parse(JAXBSource.java:222)

... 51 more

Caused by: javax.xml.stream.XMLStreamException: Prefix cannot be null

at org.apache.cxf.staxutils.StreamWriterContentHandler.startElement(StreamWriterContentHandler.java:223)

at org.xml.sax.helpers.XMLFilterImpl.startElement(XMLFilterImpl.java:527)

at com.sun.xml.bind.v2.runtime.output.SAXOutput.endStartTag(SAXOutput.java:124)

at com.sun.xml.bind.v2.runtime.XMLSerializer.endAttributes(XMLSerializer.java:302)

at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:588)

at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:312)

at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:490)

at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:325)

... 54 more

Caused by: javax.xml.stream.XMLStreamException: Prefix cannot be null

at com.sun.xml.internal.stream.writers.XMLStreamWriterImpl.writeStartElement(XMLStreamWriterImpl.java:1284)

at com.sun.xml.internal.stream.writers.XMLStreamWriterImpl.writeStartElement(XMLStreamWriterImpl.java:1262)

at org.apache.cxf.staxutils.StreamWriterContentHandler.startElement(StreamWriterContentHandler.java:197)

... 61 more

看问题好像是使用sun默认的Marshaller实现来转换Object和xml时出了问题。google上给出的答案不一,但是基本上的意思是要替换Marshaller的实现类。网上碰到类似问题的回答基本有下面几种:

1.javase6(没有细版本,我用的是1.6.0_29)的rt.jar中默认jaxb的API是2.0版本(看了一下本地jdk中jaxb的源代码,代码中没有标注版本号,但是代码中作者注释的日期是2003年,jaxb2.1的实现貌似是06年发布的),需要把jaxb2.1 api的包放到classpath中,但是事实上这个jar包已经在我的classpath中(2.1的实现中,类名和JDK的实现完全相同),于是猜想可能是class加载顺序的问题(jetty在加载class时,指定了某些类是属于System
Class,jetty关于classloading的解释:http://docs.codehaus.org/display/JETTY/Classloading),查看jetty部分源码发现jetty定义的system class规则如下(源码在org.eclipse.jetty.webapp.WebAppContext类中):

// System classes are classes that cannot be replaced by

// the web application, and they are *always* loaded via

// system classloader.

public final static String[] __dftSystemClasses =

{

"java.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)

"javax.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)

"org.xml.", // needed by javax.xml

"org.w3c.", // needed by javax.xml

"org.apache.commons.logging.", // TODO: review if special case still needed

"org.eclipse.jetty.continuation.", // webapp cannot change continuation classes

"org.eclipse.jetty.jndi.", // webapp cannot change naming classes

"org.eclipse.jetty.plus.jaas.", // webapp cannot change jaas classes

"org.eclipse.jetty.websocket.WebSocket", // WebSocket is a jetty extension

"org.eclipse.jetty.websocket.WebSocketFactory", // WebSocket is a jetty extension

"org.eclipse.jetty.servlet.DefaultServlet" // webapp cannot change default servlets

} ;

因为system class不能被overload,所以在classpath中就另外的实现类,也是会被加载的。于是想是不是把jaxb-api-2.1.jar放到jre的endorsed目录下(默认没有,自己建)是不是会优先加载,就可以覆盖掉JDK自带的实现。试了一下,还是不行。(顺便贴一篇文章名字叫: Using JAXB 2.1 with j2se 6 http://matrix.iteye.com/blog/284128

2.用Woodstox替代JDK自带的实现

从Woodstox的网站下到依赖的jar包,放到jetty的classpath中(在jetty的lib下建一个woodstox目录,在start.ini中添加该目录),一试果然成功了。把Woodstox的jar包放到endorsed目录,不添加到jetty的classpath目录,测试,不行!这个问题就有点纠结了(没想通为什么,难道是放到jre的endorsed目录的jar包没有被load?)。放到classpath下面程序在找JAXB的实现时会自动使用Woodstox的原因是因为在Woodstox的jar包中META-INF目录下的services目录下定义有javax.xml.stream.XMLEventFactory

javax.xml.stream.XMLInputFactory

javax.xml.stream.XMLOutputFactory

说实话META-INF中定义一些信息这个地方,我也没还是没弄清楚!

程序可以run起来了,还剩2个问题需要继续深入:
1.jre的endorsed的目录中的类会被当成System class优先被加载吗?会的话,为什么会出现上面的状况(woodstox的jar包放到jre的endorsed目录下不行,放到classpath下反而可以)。
2.Woodstox是怎么做到被优化作为JAXB的实现的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐