最新的 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 模式具有特定的字符串字符长度 所以我可能有一个类似的字符串 Jim Mary 在 C 中是 10 个字符 但是当它写入 xml 时 它会变成 Jim amp Mary 如果 XML 模式规定字符串最多只能有 10 个字
  • 为什么用scala写的代码比用java写的慢6倍?

    我不确定我在编写 scala 代码时是否犯了一些错误 问题是 The four adjacent digits in the 1000 digit number that have the greatest product are 9 9
  • 未装饰窗户的 Windows Snap 功能?

    有谁知道如何允许未装饰的窗户使用此功能 唯一的选择就是重新实施它 有任何想法吗 谢谢 可停靠可能是唯一的JToolBar http docs oracle com javase tutorial uiswing components too
  • JOOQ 忽略具有默认值的数据库列

    看来JOOQ完全忽略了数据库列的默认值 既不会更新 ActiveRecord 对象 也不会在 INSERT 时跳过此列 相反 它尝试将其设置为 NULL 这在 NOT NULL 列上失败 Example CREATE TABLE bug f
  • 在 XSD 中哪里放置版权信息?

    将版权信息放入 XML 架构定义 XSD 时 是否有官方 或半官方 普遍接受的 位置 基于在哪里将版本添加到 XSD 架构 https stackoverflow com questions 2138705 where to add a v
  • 如何更改 Swagger-ui URL 前缀?

    我正在使用 Springfox Swagger2 和 Spring boot 1 5 9 我可以通过此链接访问 swagger UI http localhost 8090 swagger ui html http localhost 80
  • 数据库中的持久日期不等于检索日期

    我有一个具有 Date 属性的简单实体类 此属性对应于 MySQL 日期时间列 Entity public class Entity Column name start date Temporal TemporalType TIMESTAM
  • Android - 存储对ApplicationContext的引用

    我有一个静态 Preferences 类 其中包含一些应用程序首选项和类似的内容 可以在那里存储对 ApplicationContext 的引用吗 我需要该引用 以便我可以在不继承 Activity 的类中获取缓存文件夹和类似内容 你使用的
  • 从三点求圆心的算法是什么?

    我在圆的圆周上有三个点 pt A A x A y pt B B x B y pt C C x C y 如何计算圆心 在Processing Java 中实现它 我找到了答案并实施了一个可行的解决方案 pt circleCenter pt A
  • 文本视图不显示全文

    我正在使用 TableLayout 和 TableRow 创建一个简单的布局 其中包含两个 TextView 这是代码的一部分
  • 我们如何使用 thymeleaf 绑定对象列表的列表

    我有一个表单 用户可以在其中添加任意数量的内容表对象这也可以包含他想要的列对象 就像在 SQL 中构建表一样 我尝试了下面的代码 但没有任何效果 并且当我尝试绑定两个列表时 表单不再出现 控制器 ModelAttribute page pu
  • titledBorder 标题中的图标

    您好 是否可以在 titledBorder 的标题中放置一个图标 例如以下代码 import java awt GridLayout import javax swing JFrame import javax swing JLabel i
  • 我所有的 java 应用程序现在都会抛出 java.awt.headlessException

    所以几天前我有几个工作Java应用程序使用Swing图书馆 JFrame尤其 他们都工作得很好 现在他们都抛出了这个异常 java awt headlessexception 我不知道是什么改变了也许我的Java版本不小心更新了 谢谢你尽你
  • Spring Data Rest 多对多 POST

    首先 让我解释一下我的用例 这非常简单 有一个用户实体和一个服务实体 我使用 UserService 作为连接实体 连接表 在用户和服务之间建立多对多关联最初 会有一些用户集和一些服务集 用户可以在任何时间点订阅任何服务 在这种情况下 将向
  • 使用 Apache 允许 Glassfish 和 PHP 在同一服务器中协同工作

    是否可以建立从 Java 到 php 文件的桥梁 我有一个用 Java 编写的应用程序 我需要执行http piwik org http piwik org 这是用 PHP 编写的 在服务器中 我正在运行 PHP 但无法从浏览器访问 php
  • 如何让 Firebase 与 Java 后端配合使用

    首先 如果这个问题过于抽象或不适合本网站 我想表示歉意 我真的不知道还能去哪里问 目前我已经在 iOS 和 Android 上开发了应用程序 他们将所有状态保存在 Firebase 中 因此所有内容都会立即保存到 Firebase 实时数据
  • 使用 DBCP 配置 Tomcat

    在闲置一段时间 几个小时 后 我们收到了 CommunicationsException 来自 DBCP 错误消息 在异常中 位于这个问题的末尾 但我没有看到任何配置文件中定义的 wait timeout 我们应该看哪里 在 tomcat
  • Spring 作为 JNDI 提供者?

    我想使用 Spring 作为 JNDI 提供程序 这意味着我想在 Spring 上下文中配置一个 bean 可以通过 JNDI 访问该 bean 这看起来像这样
  • 以 UTF8 而不是 UTF16 输出 DataTable XML

    我有一个 DataTable 我正在使用 WriteXML 创建一个 XML 文件 尽管我在以 UTF 16 编码导出它时遇到问题 并且似乎没有明显的方法来更改它 我了解 NET 在字符串内部使用 UTF 16 这是正确的吗 然后 我通过
  • 关闭扫描仪是否会影响性能

    我正在解决一个竞争问题 在问题中 我正在使用扫描仪获取用户输入 这是 2 个代码段 一个关闭扫描器 一个不关闭扫描器 关闭扫描仪 import java util Scanner public class JImSelection publ

随机推荐