本文介绍如何通过自定义 XmlAdapter 解决 JAXB 在解析含空格的 XML 属性值(如 "Coarse Language")时错误拆分为多个字符串的问题,并提供可编译、类型安全的绑定方案。
本文介绍如何通过自定义 `xmladapter` 解决 jaxb 在解析含空格的 xml 属性值(如 `"coarse language"`)时错误拆分为多个字符串的问题,并提供可编译、类型安全的绑定方案。
在使用 JAXB 基于 XSD 生成 Java 类时,xs:list itemType="xs:string" 会被映射为 List
直接在 XJB 绑定文件中使用
✅ 推荐解决方案:绕过泛型声明,封装带类型擦除的 List 子类
步骤一:定义类型安全的包装类
创建一个继承自 ArrayList
package com.example.adapter;
import java.util.ArrayList;
public class StringList extends ArrayList<string> {
// 空实现,仅作为 JAXB 可识别的具名类型
}</string>
步骤二:实现专用 XmlAdapter
适配器负责将属性字符串按逗号(或空格)正确分割为 StringList,同时支持序列化回原始格式(可根据实际分隔符调整):
package com.example.adapter;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import org.apache.commons.lang3.StringUtils;
public class SpaceSeparatedStringListAdapter extends XmlAdapter<string stringlist> {
@Override
public String marshal(StringList value) throws Exception {
if (value == null || value.isEmpty()) return null;
return StringUtils.join(value, " ");
}
@Override
public StringList unmarshal(String text) throws Exception {
StringList list = new StringList();
if (StringUtils.isBlank(text)) return list;
// 关键:按空格分割,但保留带空格的完整词组(如"Coarse Language")
// 注意:此处假设输入是空格分隔的独立词组,而非自由文本
// 若需更健壮解析(如支持引号包裹),建议改用正则或专用解析器
String[] items = text.split("\s+");
for (String item : items) {
if (StringUtils.isNotBlank(item)) {
list.add(item);
}
}
return list;
}
}</string>
⚠️ 注意:split("\s+") 仅适用于简单空格分隔场景。若 XML 中可能出现 "Coarse Language" 这类含空格的合法值,实际应由上游确保其以逗号分隔(如 subRatings="Violence,Coarse Language"),此时 unmarshal 应改为 StringUtils.split(text, ',') 并 trim 每项。
步骤三:配置 XJB 绑定文件
指向新类型与适配器(注意使用全限定类名):
<bindings schemalocation="media.xsd" node="//xs:complexType[@name='ratingType']"><bindings node=".//xs:attribute[@name='subRatings']"><property><basetype><javatype name="com.example.adapter.StringList" adapter="com.example.adapter.SpaceSeparatedStringListAdapter"></javatype></basetype></property></bindings></bindings>
生成效果
JAXB 将生成类型安全、无需强制转换的字段:
@XmlAttribute(name = "subRatings") @XmlJavaTypeAdapter(SpaceSeparatedStringListAdapter.class) protected StringList subRatings;
✅ 编译通过(无非法泛型导入)
✅ 类型安全(subRatings.get(0) 直接返回 String)
✅ 兼容现有代码(StringList 是 List
? 补充说明
- 此方案不修改生成类,完全通过绑定配置驱动,符合“不可修改生成代码”的约束。
- 若未来 JAXB-RI 2.3.7+ 版本合并 PR #1781(支持 java.util.List
直接声明),可回归标准泛型写法,但当前稳定版仍推荐本方案。 - 生产环境建议在 unmarshal 中增加日志或校验逻辑,对非法子评级值(如 "Coarse Language" 不在白名单中)发出告警。











