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

近日在把程序从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的实现的



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值