JAXB 在全局范围内将空字符串编组为 Null

2023-11-23

我的问题非常类似于当字符串为空但不为空时,如何防止在 JAXB 中编组空标签

不同之处在于,我无法将注释添加到 package-info.java,因为我们所有的 JAXB 类型都是从每次构建的模式生成的。 如果可能的话,我也更愿意不更改 JAXB 提供程序。

我想要实现的是,设置空字符串不会创建该元素,但我需要为来自许多模式的所有生成的 JAXB 类型进行设置。有没有办法将其应用于所有生成的 JAXB 类中的所有字符串字段?

Update通过进行以下更改,我成功地为架构中的所有字符串生成了 XML 适配器:

在项目 POM 中,我将其添加到 maven-jaxb2-plugin 中:

<bindingDirectory>src/main/resources</bindingDirectory>
<bindingIncludes>
    <include>bindings.xjb</include>
</bindingIncludes>

这是我的 bindings.xjb 文件:

<jxb:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:jxb="http://java.sun.com/xml/ns/jaxb" version="2.1">
    <jxb:globalBindings>
                    <jxb:javaType name="java.lang.String" xmlType="xs:token"
                        parseMethod="com.project.Formatter.parseString"
                        printMethod="com.project.Formatter.printString"/>
    </jxb:globalBindings>
</jxb:bindings>

以及格式化方法:

public static String printString(final String value)
{
    if (StringUtils.isBlank(value))
    {
        return null;
    }

    return value;
}

问题是这会导致 JAXB 深处出现空指针异常。这是堆栈跟踪:

Caused by: java.lang.NullPointerException
    at com.sun.xml.bind.v2.runtime.output.SAXOutput.text(SAXOutput.java:158)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.leafElement(XMLSerializer.java:321)
    at com.sun.xml.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$1.writeLeafElement(RuntimeBuiltinLeafInfoImpl.java:210)
    at com.sun.xml.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$1.writeLeafElement(RuntimeBuiltinLeafInfoImpl.java:209)
    at com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor$CompositeTransducedAccessorImpl.writeLeafElement(TransducedAccessor.java:250)
    at com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty.serializeBody(SingleElementLeafProperty.java:98)
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:322)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:681)
    at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:150)
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:322)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:681)
    at com.sun.xml.bind.v2.runtime.property.ArrayElementNodeProperty.serializeItem(ArrayElementNodeProperty.java:65)
    at com.sun.xml.bind.v2.runtime.property.ArrayElementProperty.serializeListBody(ArrayElementProperty.java:168)
    at com.sun.xml.bind.v2.runtime.property.ArrayERProperty.serializeBody(ArrayERProperty.java:152)
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:322)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:681)
    at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:150)
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:322)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:681)
    at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:150)
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:322)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:681)
    at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:150)
    at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:156)
    at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:185)
    at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeBody(ElementBeanInfoImpl.java:305)
    at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:312)
    at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:71)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:490)
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:328)
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:257)
    at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:103)

造成这个问题的原因归结为这个方法:

com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor.CompositeTransducedAccessorImpl.hasValue(BeanT)

如果值不为空,上面的方法将渲染该元素before任何适配器都运行。

有没有办法覆盖 JAXB 中使用的访问器,以便在确定是否渲染元素之前运行适配器?还有其他方法可以实现我想要的吗?


Note:我是EclipseLink JAXB (MOXy)领导者和成员JAXB (JSR-222)专家组。

您所做的是正确的,您看到的错误是由于我认为是由于JAXB 参考实现。 JAXB RI 应该能够处理从XmlAdapter。该用例适用于 EclipseLink JAXB (MOXy),我将在下面通过示例进行演示。

字符串适配器

下面是一个实现,它的作用与您从 XML 模式生成 Java 模型后将得到的实现大致相同(请参阅http://blog.bdoughan.com/2011/08/xml-schema-to-java-generate.html).

package forum11894193;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class StringAdapter extends XmlAdapter<String, String> {

    @Override
    public String marshal(String string) throws Exception {
        if("".equals(string)) {
            return null;
        }
        return string;
    }

    @Override
    public String unmarshal(String string) throws Exception {
        return string;
    }

}

包信息

由于您正在注册一个全局适配器,因此将从package-info像下面这样的类(参见:http://blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html).

@XmlJavaTypeAdapters({
    @XmlJavaTypeAdapter(value=StringAdapter.class, type=String.class)
})
package forum11894193;

import javax.xml.bind.annotation.adapters.*;

Root

下面是一个示例域类,其中包含一些String字段。自从XmlAdapter已在包级别注册,它将应用于该包中的所有映射字符串字段/属性。

package forum11894193;

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    String a;
    String b;
    String c;

}

Demo

在下面的演示代码中,我们将创建一个实例Root将几个字段设置为""然后将其编组为 XML。

package forum11894193;

import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);

        Root root = new Root();
        root.a = "";
        root.b = "b";
        root.c = "";

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);
    }

}

使用 JAXB RI 输出

在本示例中使用 JAXB RI 会导致 NPE。堆栈跟踪是不同的,但很可能我们使用不同的封送方法。我还使用 JDK 中包含的 JAXB RI 版本,该版本被重新打包为com.sun.xml.internal.bind.v2.

Exception in thread "main" java.lang.NullPointerException
    at com.sun.xml.internal.bind.v2.runtime.output.Encoded.setEscape(Encoded.java:96)
    at com.sun.xml.internal.bind.v2.runtime.output.UTF8XmlOutput.doText(UTF8XmlOutput.java:294)
    at com.sun.xml.internal.bind.v2.runtime.output.UTF8XmlOutput.text(UTF8XmlOutput.java:283)
    at com.sun.xml.internal.bind.v2.runtime.output.IndentingUTF8XmlOutput.text(IndentingUTF8XmlOutput.java:141)
    at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.leafElement(XMLSerializer.java:293)
    at com.sun.xml.internal.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$1.writeLeafElement(RuntimeBuiltinLeafInfoImpl.java:179)
    at com.sun.xml.internal.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$1.writeLeafElement(RuntimeBuiltinLeafInfoImpl.java:166)
    at com.sun.xml.internal.bind.v2.runtime.reflect.TransducedAccessor$CompositeTransducedAccessorImpl.writeLeafElement(TransducedAccessor.java:239)
    at com.sun.xml.internal.bind.v2.runtime.property.SingleElementLeafProperty.serializeBody(SingleElementLeafProperty.java:87)
    at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:306)
    at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:561)
    at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:290)
    at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:462)
    at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:314)
    at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:243)
    at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:75)
    at forum11894193.Demo.main(Demo.java:17)

使用 EclipseLink JAXB (MOXy) 输出

当 MOXy 用作 JAXB 提供程序时,您将获得所需的输出。有关指定 MOXy 作为 JAXB 提供程序的信息,请参阅:http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html.

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <b>b</b>
</root>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JAXB 在全局范围内将空字符串编组为 Null 的相关文章

随机推荐

  • 如何使用SignalR向特定用户发送数据?

    我有一个通过 SignalR 接收消息的客户端 它工作得很好 但更像是广播 我希望能够向特定客户发送消息 在客户端 我有一个 userId 并且像这样设置连接 const userId getUserId if userId const b
  • 什么是自然语言处理中的分块器?

    有谁知道文本处理上下文中的分块器是什么以及它的用途是什么 根据这些幻灯片 分块是解析的一种替代方法 它提供了句子的部分句法结构 具有有限的树深度 而不是完整的解析 它比完整解析受到更多限制 但在提取或忽略信息时就足够了 因此被多次使用 因为
  • 通过车把部分传递变量

    我目前正在express js 应用程序中处理handlebars js 为了保持模块化 我将所有模板拆分为部分模板 我的问题 我找不到通过部分调用传递变量的方法 假设我有一个看起来像这样的部分 div h1 Headline h1 p L
  • 为什么 SwitchPreference 在从打开切换到关闭时不显示动画,反之亦然?

    我做了一个SwitchPreference对于我的应用程序preferences 问题是SwitchPreference当我在打开和关闭之间切换时 它没有显示动画 而是突然猛烈地切换 Here s preferences xml文件的代码
  • 有关 Android 的 Movie 类的信息

    我正在尝试展示一个 gif 动画 顺便说一句 我正在与班级一起做Movie 但 Android 开发者页面不授予有关这些方法的信息 如何调整 gif 的大小以适应布局 提前致谢 我一直在尝试使用做同样的事情 显示动画 GIF this me
  • NumPy有相当于Matlab缓冲区的功能吗?

    我看到有一个array split and split methods但是 当您必须分割长度不是块大小整数倍的数组时 这些并不是很方便 此外 这些方法的输入是切片数量而不是切片大小 我需要一些更像 Matlab 的东西buffer更适合信号
  • mysql中的数组变量

    MySQL 脚本中有没有办法声明一个数组 或任何集合 并循环它来执行操作 例如 SET myArrayOfValue 2 5 2 23 6 for each value in myArrayOfValue INSERT INTO EXEMP
  • 如何在谷歌地图v2的默认标记中绘制文本

    我想在 Google 地图 v2 的默认标记中绘制文本 我通过从可绘制图像中获取自己的图像来完成此操作 但如何在默认标记中更改它 我的代码是 marker icon BitmapDescriptorFactory fromBitmap dr
  • Excel 过滤功能 - 选择某些列作为输出

    我想对多个列应用过滤器函数 范围从A G并且只有列B D在输出中 我该怎么做 例如 FILTER A 1 G 7 K 1 K 7 K 1 结果是匹配条件的行的溢出数组 但输出仍然有 7 列 A G 我可以选择只输出Column吗B D TL
  • ImageMagick.NET 异常

    我得到了FileNotFoundException当尝试使用 ImageMagick NET 时 取自源代码中的 bin 文件夹 http imagemagick codeplex com releases view 30302 我得到的确
  • chrome.storage 设置\获取说明

    我想在我的扩展中保存信息 我用Chrome storage sync这样做 但是当我保存后立即阅读时 我无法正确检索该值 大概是做了什么蠢事吧 我尝试清除本地存储chrome storage sync clear但这没有帮助 我的保存功能是
  • 使用 .htaccess 密码保护单个文件

    我尝试使用 htaccess 对单个文件进行密码保护 但是 当访问该文件时 浏览器只会重定向到网站的主页 我的 webroot 上有 htpasswd 我的 htaccess 文件如下
  • 在 SQL Server 2005 中,如何设置整数列以确保值大于 0?

    这可能是一个简单的答案 但我找不到它 我有一个包含整数列的表 我想确保插入行时该列中的值大于零 我可以在代码方面执行此操作 但认为最好在桌面上强制执行它 Thanks 我上次的评论是错误的 现在一切都很好 您可以在列上使用检查约束 IIRC
  • 隐藏 ag-grid 中的列名称?

    是否可以隐藏 ag grid 中的第一行 列定义 我只想显示表中的数据并排除列标题 你可以加headerHeight组件上的属性并将其设置为 0 这将隐藏标头 就像这样
  • R:shapefile 上的梯度图

    我目前有一个英国的形状文件 并绘制了英国不同地区的物种数量 到目前为止 我刚刚绘制了 3 个物种种群水平 并将它们着色为红色 高 橙色 中 绿色 低 但我想做的是绘制一个渐变图 而不是仅受 3 种颜色的限制 到目前为止 我有一个名为 计数
  • VS2010 中的 Magick++ - 无法解析的外部符号

    我正在尝试在 VS2010 中使用 ImageMagick Magick 进行 C 项目 我从这里安装了库 klick 然后在我的项目中 我将 c program files ImageMagick 6 6 6 Q16 include 添加
  • 为什么 PHP 认为 0 等于字符串?

    我有以下代码 item price 0 Code to get item information goes in here if item price e item price 1 其目的是将商品价格初始化为 0 然后获取有关它的信息 如果
  • 为 MKOverlayView 制作动画

    我有一个 MKOverlayView 它将动画雷达数据显示为一系列图像 我遇到的问题是雷达图像被 MapKit 切成图块 为了交换图像 我有一个计时器 它调用更新函数 该函数在叠加层中设置当前图像 然后调用以下命令 myRadarOverl
  • 涉及具有易失性变量的表达式的简单语句的正确行为?

    考虑以下陈述 volatile int a 7 a statement A volatile int b a b statement B volatile int c a c statement C 现在 我一直试图在标准中找到一个点 告诉
  • JAXB 在全局范围内将空字符串编组为 Null

    我的问题非常类似于当字符串为空但不为空时 如何防止在 JAXB 中编组空标签 不同之处在于 我无法将注释添加到 package info java 因为我们所有的 JAXB 类型都是从每次构建的模式生成的 如果可能的话 我也更愿意不更改 J