含非ASCII值枚举的XSD生成Java类问题(Java17+Gradle XJC)
使用Java 17及Gradle插件com.github.bjornvester.xjc(版本1.8.2),需从XSD Schema生成Java类,用于读取含非ASCII字符的数据库值,后续还要将Java对象编组为可验证的XML字符串。
XSD中多处枚举包含非ASCII字符,示例如下:
<xsd:complexType name="NyType"> <xsd:sequence> <xsd:element name="number" type="xsd:integer"/> <xsd:element name="myEnumType" type="MyEnumType"/> </xsd:sequence> </xsd:complexType> <xsd:simpleType name="MyEnumType"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="ÄNt"/> <xsd:enumeration value="Al-sör"/> <xsd:enumeration value="Sår"/> </xsd:restriction> </xsd:simpleType>
生成时出现编码错误:
error: unmappable character (0xF6) for encoding UTF-8
以及:
error: illegal character: '�'
生成的Java枚举示例:
@XmlEnumValue("ÄNt") Ä_NT("ÄNt"), @XmlEnumValue("AL-sör") AL_SÖR("AL-sör"),
修改XSD中åäöÖÅÄ为aAoO可正常生成,但会导致数据库值与枚举不匹配。尝试通过XJC绑定文件修改枚举名称:
<jaxb:bindings node="//xsd:simpleType[@name='MyEnumType']/xsd:restriction/xsd:enumeration[@value='ÄNt']"> <jaxb:typesafeEnumMember name="ANT"/> </jaxb:bindings>
修改后枚举变为:
@XmlEnumValue("ÄNt") ANT("ÄNt");
部分错误消失,但编码错误仍存在(指向生成的JavaDoc注释)。现需解决:
- 如何同时替换枚举值?
- 或如何配置绑定文件让XJC不生成枚举值?
- 若解决生成问题,能否正确映射数据库值并生成符合验证的XML?
一、彻底解决编码错误的核心配置
编码错误本质是XJC生成Java文件时的编码与项目编码不匹配,或者XSD文件本身的编码未正确声明,按以下两步处理:
- 给XSD文件添加UTF-8编码声明
在XSD文件最顶部添加:<?xml version="1.0" encoding="UTF-8"?> - 配置Gradle XJC插件的编码参数
在build.gradle中指定XJC生成文件时使用UTF-8:
这一步能解决JavaDoc注释和枚举名称中的非ASCII字符编码问题,无需手动修改枚举值。xjc { encoding = 'UTF-8' // 保留其他已有配置 }
二、绑定文件进阶:规范枚举名称+保留原始枚举值
如果需要统一枚举名称格式(比如全大写无特殊字符),同时保留原始非ASCII枚举值用于映射,完善绑定文件即可:
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="2.3"> <jaxb:bindings schemaLocation="你的XSD文件路径.xsd"> <!-- 逐个配置枚举项的Java名称 --> <jaxb:bindings node="//xsd:simpleType[@name='MyEnumType']/xsd:restriction/xsd:enumeration[@value='ÄNt']"> <jaxb:typesafeEnumMember name="ANT"/> </jaxb:bindings> <jaxb:bindings node="//xsd:simpleType[@name='MyEnumType']/xsd:restriction/xsd:enumeration[@value='Al-sör']"> <jaxb:typesafeEnumMember name="AL_SOR"/> </jaxb:bindings> <jaxb:bindings node="//xsd:simpleType[@name='MyEnumType']/xsd:restriction/xsd:enumeration[@value='Sår']"> <jaxb:typesafeEnumMember name="SAR"/> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings>
生成后的枚举会是:
@XmlEnumValue("ÄNt") ANT("ÄNt"), @XmlEnumValue("Al-sör") AL_SOR("Al-sör"), @XmlEnumValue("Sår") SAR("Sår");
这样既规范了Java代码中的枚举名称(避免非ASCII字符),又保留了原始枚举值,完全不影响数据库值映射和XML验证。
三、让XJC不生成枚举,改用字符串类型
如果不想生成枚举类型,可通过绑定文件将指定的simpleType映射为Java的String类型:
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="2.3"> <jaxb:bindings schemaLocation="你的XSD文件路径.xsd"> <jaxb:bindings node="//xsd:simpleType[@name='MyEnumType']"> <jaxb:javaType name="java.lang.String"/> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings>
生成的NyType类中,myEnumType字段会是String类型而非枚举。注意:这种方式会失去XSD枚举的自动验证能力,需要自行在代码中处理值的合法性校验。
四、数据库映射与XML验证的兼容性说明
只要解决了编码问题,且保留了XSD中原始的枚举值(不管用枚举类型还是字符串类型):
- 数据库映射:用枚举的
value()方法可直接获取原始非ASCII字符串,与数据库值完全匹配;字符串类型则直接存储/读取即可。 - XML验证:JAXB在编组时会使用
@XmlEnumValue指定的原始值生成XML,完全符合XSD验证规则;字符串类型只要值符合XSD枚举约束,也能通过验证。
内容的提问来源于stack exchange,提问作者StarMcSnow

