草庐IT

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

coder 2024-04-01 原文

我在 Ubuntu 16.04 上使用 Java。最近我升级到使用 oracle-java8-installer 包安装的 Open JDK java 版本“1.8.0_161”(包版本 8u161-1~webupd8~0)。自从进行此升级后,我在对 Java 对象进行 JAXB 编码时遇到了新的异常。

具体来说,当尝试使用 JAXB 将 Java 对象编码为 XML 时,如果 Java 对象具有包含任何换行符(“\n”)字符的 String 属性并且该 String 属性被序列化为元素,我会得到以下异常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 Newlines in JAXB string values of SOAP-requests are escaped to "&#xa;"

this stack overflow question 的答案建议我可以通过让编码器使用 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 通过 StAX/WoodStox 将一些对象转换为 XML 并将它们序列化为一个文件。我设法通过过滤正在序列化的 XML 来解决问题。详细来说,方法是这样的:

  1. 定义自定义 StreamWriter2Delegate , 覆盖 writeEntityRef() ,因此,当此方法接收到错误的实体代码(#xd#xa)时,它会调用其委托(delegate)来实际写回原始字符(即 \n\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 );
    }
    

这相当于(除了一些开销)fix they've already filed对于这个问题,JDK8u192 应该可用(并且应该已经在 J​​DK 9/10 中)。

  1. 包装你的 XMLStreamWriter2使用上述过滤器,例如:

    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 .将相同的方法应用于类似的管道应该不难(一般来说,问题的发生是因为 com.sun.xml.internal.bind.v2.runtime.output.XMLStreamWriterOutput 转义了 \n\r 是错误的方式,所以诀窍是从上层劫持这种错误的编码。

关于java - 最新的 Open JDK 8 JAXB 库无法解码具有包含换行符的属性的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48603942/

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

  1. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  2. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  3. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  4. ruby-on-rails - Rails 3.1 中具有相同形式的多个模型? - 2

    我正在使用Rails3.1并在一个论坛上工作。我有一个名为Topic的模型,每个模型都有许多Post。当用户创建新主题时,他们也应该创建第一个Post。但是,我不确定如何以相同的形式执行此操作。这是我的代码:classTopic:destroyaccepts_nested_attributes_for:postsvalidates_presence_of:titleendclassPost...但这似乎不起作用。有什么想法吗?谢谢! 最佳答案 @Pablo的回答似乎有你需要的一切。但更具体地说...首先改变你View中的这一行对此#

  5. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  6. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  7. 报告回顾丨模型进化狂飙,DetectGPT能否识别最新模型生成结果? - 2

    导读语言模型给我们的生产生活带来了极大便利,但同时不少人也利用他们从事作弊工作。如何规避这些难辨真伪的文字所产生的负面影响也成为一大难题。在3月9日智源Live第33期活动「DetectGPT:判断文本是否为机器生成的工具」中,主讲人Eric为我们讲解了DetectGPT工作背后的思路——一种基于概率曲率检测的用于检测模型生成文本的工具,它可以帮助我们更好地分辨文章的来源和可信度,对保护信息真实、防止欺诈等方面具有重要意义。本次报告主要围绕其功能,实现和效果等展开。(文末点击“阅读原文”,查看活动回放。)Ericmitchell斯坦福大学计算机系四年级博士生,由ChelseaFinn和Chri

  8. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  9. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  10. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

随机推荐