如何为XSD生成类的List<String>属性添加自定义JAXB XML适配器
解决JAXB解析带空格的list属性问题
问题背景
我们长期使用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>
默认生成的Java属性
未做任何修改时,JAXB生成的对应Java类属性如下:
@XmlAttribute(name = "subRatings") protected List<String> subRatings;
解析行为异常场景
当前正常场景:
XML内容:<rating scheme="urn:ncs" subRatings="Violence">MA15+</rating>解析后
subRatings=["Violence"],符合预期。新异常场景:
XML内容:<rating scheme="urn:ncs" subRatings="Coarse Language">MA15+</rating>JAXB默认按空格拆分list项,解析后
subRatings=["Coarse", "Language"],不符合我们需要的subRatings=["Coarse Language"],会导致下游系统出错。
尝试的绑定配置及问题
我们尝试通过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的名称改为java.util.List,JAXB会生成原始类型字段protected List subRatings;,不仅不符合规范,还会导致下游使用时需要强制类型转换,代码可读性差。注意:我们无法修改编译时生成的类,必须通过绑定配置解决问题。
解决方案
通过在绑定配置中添加<jxb:genericType>指定泛型参数,同时保持<xjc:javaType>的name为java.util.List,即可生成正确的泛型字段和导入语句。
修改后的绑定配置:
<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" adapter="org.jvnet.jaxb2_commons.xml.bind.annotation.adapters.CommaDelimitedStringAdapter"/> </jxb:baseType> <jxb:genericType>java.util.List<java.lang.String></jxb:genericType> </jxb:property> </jxb:bindings> </jxb:bindings>
配置说明
<xjc:javaType>指定基础类型为java.util.List,避免生成错误的泛型导入语句;<jxb:genericType>明确指定泛型参数为java.util.List<java.lang.String>,让JAXB生成带泛型的字段定义;- 使用
CommaDelimitedStringAdapter后,JAXB会按逗号拆分subRatings的值,而不是默认的空格,因此"Coarse Language"会被解析为单个List元素,符合业务需求。
生成的正确代码如下:
import java.util.List; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import org.jvnet.jaxb2_commons.xml.bind.annotation.adapters.CommaDelimitedStringAdapter; // ... 其他类定义 @XmlAttribute(name = "subRatings") @XmlJavaTypeAdapter(CommaDelimitedStringAdapter.class) protected List<String> subRatings;
内容的提问来源于stack exchange,提问作者CjRobin
相关产品推荐
相关产品推荐

