我在 Ubuntu 16.04 上使用 Java。最近我升级到使用 oracle-java8-installer 包(包版本 8u161-1~webupd8~0)安装的 Open JDK java 版本“1.8.0_161”。自从进行此升级以来,我在对 Java 对象进行 JAXB 编组时遇到了新的异常。
具体来说,当尝试使用 JAXB 将 Java 对象编组为 XML 时,如果 Java 对象具有包含任何换行符(“\n”)字符的 String 属性,并且该 String 属性被序列化为 XML 中的元素内容,则会出现以下异常: XML。 (顺便说一句,如果 String 属性被序列化为属性内容,则 String 值中的任何换行符都会转换为空格字符,并且不会触发异常。)
似乎正在发生的事情是
com.sun.xml.internal.bind.v2.runtime.output.XMLStreamWriterOutput$NewLineEscapeHandler.escape
将Java对象的String属性中的换行符转换为实体引用

。然后,该实体引用被写入 XML 输出流,但在验证实体引用名称时,会引发异常,因为 #xa 未被识别为有效的实体引用名称。
这是预期的行为吗?如果是这样,我应该怎样做才能在Java对象的序列化中保留换行符?如果不是,我应该怎么做才能解决这个问题?
堆栈跟踪的相关部分是:
... Caused by: javax.xml.stream.XMLStreamException: Invalid name start character '#' (code 35) (name "#xa")
at com.fasterxml.aalto.out.XmlWriter.throwOutputError(XmlWriter.java:472)
at com.fasterxml.aalto.out.XmlWriter.reportNwfName(XmlWriter.java:383)
at com.fasterxml.aalto.out.ByteXmlWriter.verifyNameComponent(ByteXmlWriter.java:235)
at com.fasterxml.aalto.out.ByteXmlWriter.constructName(ByteXmlWriter.java:181)
at com.fasterxml.aalto.out.WNameTable.findSymbol(WNameTable.java:324)
at com.fasterxml.aalto.out.StreamWriterBase.writeEntityRef(StreamWriterBase.java:615)
at net.galexy.fieldguide.jaxb.CustomXMLStreamWriter.writeEntityRef(CustomXMLStreamWriter.java:198)
at com.sun.xml.internal.bind.v2.runtime.output.XMLStreamWriterOutput$XmlStreamOutWriterAdapter.writeEntityRef(XMLStreamWriterOutput.java:277)
at com.sun.xml.internal.bind.v2.runtime.output.XMLStreamWriterOutput$NewLineEscapeHandler.escape(XMLStreamWriterOutput.java:242)
... 60 more
例如,如果我解组以下 XML:
<?xml version='1.0' encoding='UTF-8'?>
<description>
<note>The text of the note</note>
</description>
然后尝试将其编组回 XML,则不会引发异常。
但是,如果注释内容中间有一个新行:
<?xml version='1.0' encoding='UTF-8'?>
<description>
<note>The text of
the note</note>
</description>
然后抛出异常。
正在使用的 JAXB 上下文是com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl
.
正在使用的 JAXB 编组器是com.sun.xml.internal.bind.v2.runtime.MarshallerImpl
在寻找有关这些更改的更多信息时,我发现了以下错误报告,该报告表明其他人在此版本的 JAXB 中也遇到了相同的更改:
JDK-8196491 SOAP 请求的 JAXB 字符串值中的换行符转义为“
” https://bugs.openjdk.java.net/browse/JDK-8196491?jql=project%20%3D%20JDK%20AND%20component%20%3D%20xml
答案是这个堆栈溢出问题 https://stackoverflow.com/questions/3289036/how-to-prevent-jaxb-escaping-a-string%20StackOverflow%20question建议我可以通过让我的编组器使用自定义实现来恢复对字符转义的控制com.sun.xml.bind.marshaller.CharacterEscapeHandler
.
这让我很困惑,因为javax.xml.bind.Marshaller
似乎没有声明静态属性名称com.sun.xml.bind.marshaller.CharacterEscapeHandler
虽然它确实声明了其他属性名称,例如Marshaller.JAXB_FORMATTED_OUTPUT
,等于"jaxb.formatted.output
.
即使我可以指示编组器使用我的自定义字符转义处理程序,我也不完全确定我应该在该转义处理程序中做什么。是否有一个合适的基本转义处理程序,我可以重写它来继承所有标准转义处理,以确保我进行干预以停止换行符的转义?
我也尝试过Oracle Java 9(软件包版本9.0.4-1~webupd8~0),该版本的Java也有同样的问题。
我还尝试了 Oracle Java 8 的下一个版本 (1.8.0_162),该版本也存在相同的问题。
从 Oracle 网站 (1.8.0_152) 下载旧版本的 Java 可以解决问题,但并不是解决问题的令人满意的方法。