提问人:CjRobin 提问时间:5/20/2023 最后编辑:CjRobin 更新时间:11/13/2023 访问量:86
如何将自定义字符串添加到 List<String> JSD 生成的类属性的 jaxb xml 适配器
How to add custom String to List<String> jaxb xml adapter to an xsd generated class attribute
问:
长期以来,我们一直在使用 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<String>" 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.List
protected List subRatings;
答:
不知道你是否找到了解决问题的方法,但也许这可以工作:
- 创建一个新的 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;
解组是可以的,请参阅此处,您仍然可以在没有任何强制转换的情况下浏览列表项。
我发现的唯一缺点是您必须选择您正在使用的实现(我选择,因为这是适配器方法中使用的实现,但它可以与任何其他类型的方法一起使用)。List
LinkedList
unmarshalling
评论
import java.util.List<String>;
”- 生成无效的 Java 代码会表明存在错误,不是吗?您可能需要检查错误数据库以查看是否列出了此问题?