最新的 Open JDK 8 JAXB 库无法解组具有包含换行符的属性的对象

2024-04-23

我在 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 可以解决问题,但并不是解决问题的令人满意的方法。


就我而言,我使用 JAXB 将一些对象转换为 XML,并通过 StAX/WoodStox 将它们序列化为文件。我已经通过过滤正在序列化的 XML 设法解决了有问题的问题。详细来说,该方法是这样的:

  1. 定义一个自定义StreamWriter2Delegate http://atetric.com/atetric/javadoc/org.codehaus.woodstox/stax2-api/3.0.1/org/codehaus/stax2/util/StreamWriter2Delegate.html, 覆盖writeEntityRef() http://atetric.com/atetric/javadoc/org.codehaus.woodstox/stax2-api/3.0.1/org/codehaus/stax2/util/StreamWriterDelegate.html#writeEntityRef-java.lang.String-,这样,当该方法接收到错误的实体代码时(#xd or #xa),它调用其委托来实际写回原始字符(即,\n or \r),实际上不需要转义:

    @Override
    public void writeEntityRef ( String eref ) throws XMLStreamException
    {
        if ( eref == null || !eref.startsWith ( "#x" ) ) {
            super.writeEntityRef ( eref );
            return;
        }
        String hex = eref.substring ( 2 );
        for ( char c: new char[] { '\r', '\n' } )
            if ( Integer.toHexString ( c ).equals ( hex ) ) {
                this.writeCharacters ( Character.toString ( c ) );
                return;
        }
        super.writeEntityRef ( eref );
    }
    

这相当于(除了一些开销)修复他们已经提交的问题 http://hg.openjdk.java.net/jdk8u/jdk8u-dev/jaxws/rev/6ac8c8bf6b78对于这个问题,它应该在 JDK8u192 中可用(并且应该已经在 J​​DK 9/10 中)。

  1. 包裹你的XMLStreamWriter2 https://github.com/FasterXML/stax2-api/blob/master/src/main/java/org/codehaus/stax2/XMLStreamWriter2.java使用上述过滤器,例如:

    FileOutputStream fout = new FileOutputStream ( "test.xml" );
    WstxOutputFactory wsof = (WstxOutputFactory) WstxOutputFactory.newInstance();
    XMLStreamWriter2 xmlOut = (XMLStreamWriter2) wsof.createXMLStreamWriter ( fout, CharsetNames.CS_UTF8 );
    xmlOut = new NewLineFixWriterFilter ( xmlOut );
    // Now write into xmlOut, directly or via JAXB
    

完整/生产代码是here https://github.com/Rothamsted/knetbuilder/blob/master/ondex-knet-builder/modules/oxl/src/main/java/net/sourceforge/ondex/oxl/jaxb/NewLineFixWriterFilter.java。对相似的管道采用相同的方法应该不难(一般来说,出现问题的原因是com.sun.xml.internal.bind.v2.runtime.output.XMLStreamWriterOutput逃脱\n and \r错误的方式,所以技巧是从上层劫持这个错误的编码)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

最新的 Open JDK 8 JAXB 库无法解组具有包含换行符的属性的对象 的相关文章

  • 直接将 XML 写入磁盘并附加元素

    我正在尝试编写一个 XML 文件 但它太大而无法存储在内存中 因此我想将其直接写入磁盘 我尝试过使用 XmlWriter 但没有功能使我能够附加到文件末尾 因此我愿意使用常规文件编写器来编写 XML 原始数据 有谁知道任何文件写入类使我能够
  • 由于连接超时,无法通过 ImageIO.read(url) 获取图像

    下面的代码似乎总是失败 URL url new URL http userserve ak last fm serve 126 8636005 jpg Image img ImageIO read url System out printl
  • 如何从另一个xml文件动态更新xml文件?

    我想从另一个 xml 文件更新 xml 文件 我使用了一个 xml 文件 如下所示 one xml
  • JTree 节点不会被直观地选择

    不知何故 我无法为我的 JTree 节点启用 选择突出显示 我正在我的项目中使用自定义单元格渲染器 这很可能导致此问题 这是完整的渲染器类代码 protected class ProfessionTreeCellRenderer exten
  • Java 泛型/类型调度问题

    考虑以下程序 import java util List import java util ArrayList public class TypeTest public static class TypeTestA extends Type
  • 如何解决 onEditCommit 事件上的类型不匹配错误?

    我在 Fxml 中使用 onEditCommit 事件在用户编辑数据后检索数据 FXML 代码
  • 方法断点可能会大大减慢调试速度

    每当向方法声明行添加断点 在 Intellij IDEA 或 Android Studio 中 时 都会出现一个弹出窗口 方法断点可能会大大减慢调试速度 为什么会这样戏剧性地减慢调试速度 是我的问题吗 将断点放在函数的第一行有什么不同 Th
  • spring - 强制 @Autowired 字段的 cglib 代理

    我有混合堆栈 EJB 和 Spring 为了将 Spring 自动装配到 EJB 我使用SpringBeanAutowiringInterceptor 不确定这是否会影响我遇到的问题 在尝试通过以下方式自动装配 bean 时 Scope p
  • Java替换特定字符

    这是我在这个网站上的第一个问题 所以我会尽量不要成为一个十足的菜鸟 我目前正在用java 创建刽子手游戏 所以我问你的问题是我们是否被赋予了 幽灵 这个词 并将 Ghost 替换为 hiddenWord ghost length for i
  • ROWNUM 的 OracleType 是什么

    我试图参数化所有现有的 sql 但以下代码给了我一个问题 command CommandText String Format SELECT FROM 0 WHERE ROWNUM lt maxRecords command CommandT
  • Java:VM 如何在 32 位处理器上处理 64 位“long”

    JVM 如何在 32 位处理器上处理 64 位的原始 long 在多核 32 位机器上可以并行利用多个核心吗 64 位操作在 32 位机器上慢了多少 它可能使用多个核心来运行不同的线程 但不会并行使用它们进行 64 位计算 64 位长基本上
  • 参数动态时如何构建 JPQL 查询?

    我想知道是否有一个好的解决方案来构建基于过滤器的 JPQL 查询 我的查询太 富有表现力 我无法使用 Criteria 就像是 query Select from Ent if parameter null query WHERE fiel
  • 如何在java中使jpeg无损?

    有没有人可以告诉我如何使用编写 jpeg 文件losslessjava中的压缩 我使用下面的代码读取字节来编辑字节 WritableRaster raster image getRaster DataBufferByte buffer Da
  • 为什么 ConcurrentHashMap::putIfAbsent 比 ConcurrentHashMap::computeIfAbsent 更快?

    使用 ConcurrentHashMap 我发现computeIfAbsent 比putIfAbsent 慢两倍 这是简单的测试 import java util ArrayList import java util List import
  • 从 html 页面和 javascript 调用 java webservice

    我正在尝试从 javascript 调用 java 实现的 Web 服务 使用 NetBeans IDE 我读过很多关于 jQuery 和 AJAX 的内容 但我似乎无法掌握它 假设我的 Web 服务 WSDL 位于 http localh
  • APEX:从临时表下载 BLOB

    我正在尝试使用 Oracle APEX 4 1 1 构建一个简单的查看应用程序 要显示的信息位于与包含 APEX 应用程序访问的架构的数据库不同的数据库上的表中 使用视图 View 访问此远程表 远程表视图 和数据库链接 视图按预期工作 包
  • 来自客户端的超时 Web 服务调用

    我正在使用 RestEasy 客户端调用网络服务 一项要求是 如果调用运行时间超过 5 秒 则中止 超时调用 我如何使用 RestEasy 客户端实现这一目标 我只看到服务器端超时 即如果在一定时间内未完成请求 Rest Easy 网络服务
  • 从java中的字符串数组中删除空值

    java中如何从字符串数组中删除空值 String firstArray test1 test2 test4 我需要像这样没有 null 空 值的 firstArray String firstArray test1 test2 test4
  • 如何将实例变量传递到 Quartz 作业中?

    我想知道如何在 Quartz 中外部传递实例变量 下面是我想写的伪代码 如何将 externalInstance 传递到此作业中 public class SimpleJob implements Job Override public v
  • Java 推断泛型类型

    我正在寻找类似的推断捕获泛型类型的概念 类似于以下方法片段 但不是捕获泛型类型的类 public

随机推荐