如何将自定义字符串添加到 List<String> JSD 生成的类属性的 jaxb xml 适配器

How to add custom String to List<String> jaxb xml adapter to an xsd generated class attribute

提问人:CjRobin 提问时间:5/20/2023 最后编辑:CjRobin 更新时间:11/13/2023 访问量:86

问:

长期以来,我们一直在使用 jaxb 将 XML 解组为可以在系统中使用的 POJO。但是,直到最近,我才发现 jaxb 如何解析 xml 提供的数据存在问题,我想通过实现自定义 XmlAdapter 并强制 jaxb 使用它来覆盖该行为。

假设我们在 xsd 中有一个复杂的字段定义,如下所示:

<xs:complexType name="ratingType">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="scheme" use="required" type="xs:NMTOKEN"/>
        <xs:attribute name="subRatings" use="optional">
          <xs:simpleType>
            <xs:list itemType='xs:string'/>
          </xs:simpleType>
        </xs:attribute>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>

在不进行任何更改的情况下,jaxb 将创建以下 java 类属性:

@XmlAttribute(name = "subRatings")
protected List<String>subRatings;

这通常是可以的,但是,由于新的客户要求,我们在这个领域获得的数据将发生变化。

当前用例:这变成了 subRatings=[“Violence”],这很棒。<rating scheme="urn:ncs" subRatings="Violence">MA15+</rating>

新用例:但是,这会变成 subRatings=[“Coarse”, “Language”],这是不正确的,并且会导致下游问题,因为这不是可识别的 subRating。我希望它是subRatings=[“Coarse Language”]。<rating scheme="urn:ncs" subRatings="Coarse Language">MA15+</rating>

我已经尝试了一些方法,但到目前为止,最接近我想要的东西的是使用 jaxb 绑定,如下所示:

<jxb:bindings schemaLocation="media.xsd" node="//xs:complexType[@name='ratingType']">
        <jxb:bindings node=".//xs:attribute[@name='subRatings']">
            <jxb:property>
                <jxb:baseType>
                    <xjc:javaType name="java.util.List&lt;String&gt;" adapter="org.jvnet.jaxb2_commons.xml.bind.annotation.adapters.CommaDelimitedStringAdapter"/>
                </jxb:baseType>
            </jxb:property>
        </jxb:bindings>
    </jxb:bindings>

生成的类具有以下属性定义:

@XmlAttribute(name = "subRatings")
    @XmlJavaTypeAdapter(CommaDelimitedStringAdapter.class)
    protected List<String>subRatings;

到目前为止一切都很好。但是,由于某种原因,jaxb 将此导入添加到类中:这会导致它无法编译。import java.util.List<String>;

我尝试的另一件事是删除 javaType 名称定义中的特定类型,例如,但这会导致 jaxb 创建具有原始类型的字段,这不仅丑陋,而且会导致下游出现问题,因为现在使用此类的任何人都需要强制转换子评级对象,使代码变得臭味。有什么想法可以克服这个问题吗?请记住,我无法修改生成的类,因为它们是在编译时构建的。java.util.Listprotected List subRatings;

java xsd xml 解析 maven-jaxb2-plugin

评论

0赞 Jim Garrison 5/20/2023
“jaxb 将此导入添加到类中:import java.util.List<String>;- 生成无效的 Java 代码会表明存在错误,不是吗?您可能需要检查错误数据库以查看是否列出了此问题?
0赞 FLUXparticle 5/21/2023
列表的分隔符应该是什么?
0赞 CjRobin 5/22/2023
@FLUXparticle逗号 (“,”) 分隔。
0赞 FLUXparticle 5/23/2023
那么我想说的是,在XML模式中描述这种格式是不可能的。至少不是以自动处理列表的方式。在 XML 架构中,列表始终由空格分隔。

答:

0赞 Laurent Schoelens 11/13/2023 #1

不知道你是否找到了解决问题的方法,但也许这可以工作:

  • 创建一个新的 Java 类,该类扩展该类以屏蔽来自LinkedList<String>
public class ListString extends LinkedList<String> {

}
  • 创建适配器(受您使用的类的启发)
public class CommaDelimitedStringAdapter extends
    XmlAdapter<String, ListString> {

    @Override
    public String marshal(ListString value) throws Exception {
        if (value == null) {
            return null;
        } else {
            return StringUtils.join(value.iterator(), ", ");
        }
    }

    @Override
    public ListString unmarshal(String text) throws Exception {

        if (text == null) {
            return null;
        } else

        {
            final ListString value = new ListString();
            final String[] items = StringUtils.split(text, ',');
            for (String item : items) {
                final String trimmedItem = item.trim();
                if (!StringUtils.isEmpty(trimmedItem)) {
                    value.add(trimmedItem);
                }
            }
            return value;
        }
    }
}
  • 调整绑定文件,使其使用您创建的新适配器来使用它xjc:javaType name="fully.qualified.package.ListString"

这将生成以下属性:

    @XmlAttribute(name = "subRatings")
    @XmlJavaTypeAdapter(CommaDelimitedStringAdapter.class)
    protected ListString subRatings;

解组是可以的,请参阅此处,您仍然可以在没有任何强制转换的情况下浏览列表项。

我发现的唯一缺点是您必须选择您正在使用的实现(我选择,因为这是适配器方法中使用的实现,但它可以与任何其他类型的方法一起使用)。ListLinkedListunmarshalling