如何为JAXB2从XSD生成的Java代码添加额外JSON注解
解决JAXB生成枚举在Jackson/RestEASY中的序列化反序列化问题
我完全懂你遇到的痛点——JAXB生成的枚举在XML服务里跑的顺风顺水,一转到REST用Jackson就掉链子,核心就是这些枚举类缺了Jackson需要的注解。下面给你几个实用的解决方案,按推荐程度排序:
方案1:通过XSD绑定文件注入注解(推荐)
直接在XSD生成Java代码的阶段,就让JAXB自动加上Jackson的注解,一劳永逸。
两种实现方式:
方式A:用JAXB原生绑定+Javadoc注入代码
创建一个绑定文件(比如jaxb-binding.xml),给所有枚举类自动生成@JsonValue和@JsonCreator相关代码:<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema" jaxb:version="2.1"> <jaxb:bindings schemaLocation="your-schema.xsd" node="/xs:schema"> <jaxb:globalBindings> <jaxb:typesafeEnumClass> <xjc:javadoc> @com.fasterxml.jackson.annotation.JsonValue public String getValue() { try { return this.getClass().getField(this.name()) .getAnnotation(javax.xml.bind.annotation.XmlEnumValue.class) .value(); } catch (NoSuchFieldException e) { return this.name(); } } @com.fasterxml.jackson.annotation.JsonCreator public static {ENUM_NAME} fromValue(String value) { for ({ENUM_NAME} e : values()) { if (e.getValue().equals(value)) { return e; } } throw new IllegalArgumentException("Invalid value: " + value); } </xjc:javadoc> </jaxb:typesafeEnumClass> </jaxb:globalBindings> </jaxb:bindings> </jaxb:bindings>然后在Maven的
jaxb2-maven-plugin配置中引入这个绑定文件即可。方式B:用
jaxb2-annotate-plugin直接加注解
这个插件更灵活,无需写代码片段,直接在绑定文件中指定要添加的Jackson注解:<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:annox="http://annox.dev.java.net" jaxb:version="2.1"> <jaxb:bindings schemaLocation="your-schema.xsd" node="/xs:schema"> <!-- 给特定枚举类加注解 --> <jaxb:bindings node="//xs:simpleType[@name='YourEnumType']"> <annox:annotateClass>@com.fasterxml.jackson.annotation.JsonFormat(shape = com.fasterxml.jackson.annotation.JsonFormat.Shape.STRING)</annox:annotateClass> <!-- 给枚举的value方法加@JsonValue --> <jaxb:bindings node="//xs:enumeration"> <annox:annotateMethod method="getValue">@com.fasterxml.jackson.annotation.JsonValue</annox:annotateMethod> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings>记得在Maven依赖中添加这个插件,让它在代码生成阶段生效。
方案2:启用Jackson的JAXB兼容模块
如果不想修改XSD或生成配置,可以让Jackson直接识别JAXB的注解,无需额外添加Jackson注解。
步骤:
- 添加Jackson JAXB模块依赖:
<dependency> <groupId>com.fasterxml.jackson.module</groupId> <artifactId>jackson-module-jaxb-annotations</artifactId> <version>${jackson.version}</version> </dependency> - 在RestEASY中注册该模块:
- 若用Spring Boot,只需把模块注册为Bean:
@Bean public Module jaxbAnnotationModule() { return new JaxbAnnotationModule(); } - 原生RestEASY则需配置到
JacksonJaxbJsonProvider:JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider(); provider.registerModule(new JaxbAnnotationModule()); // 将provider注册到RestEASY环境
@XmlEnum、@XmlEnumValue注解,完美适配枚举的序列化反序列化。 - 若用Spring Boot,只需把模块注册为Bean:
方案3:自定义Jackson枚举序列化器/反序列化器
如果上面两种方案不适用,可以写通用的枚举序列化逻辑,适配JAXB生成的枚举。
示例代码:
// 序列化器:读取@XmlEnumValue的值输出 public class JaxbEnumSerializer extends StdSerializer<Enum<?>> { public JaxbEnumSerializer() { super(Enum.class, true); } @Override public void serialize(Enum<?> value, JsonGenerator gen, SerializerProvider provider) throws IOException { try { Field field = value.getClass().getField(value.name()); XmlEnumValue annotation = field.getAnnotation(XmlEnumValue.class); gen.writeString(annotation != null ? annotation.value() : value.name()); } catch (NoSuchFieldException e) { gen.writeString(value.name()); } } } // 反序列化器:匹配@XmlEnumValue或枚举name() public class JaxbEnumDeserializer extends StdDeserializer<Enum<?>> { public JaxbEnumDeserializer() { super(Enum.class); } @Override @SuppressWarnings("unchecked") public Enum<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String inputValue = p.getText(); Class<?> enumClass = ctxt.getContextualType().getRawClass(); for (Enum<?> enumVal : (Enum<?>[]) enumClass.getEnumConstants()) { try { Field field = enumClass.getField(enumVal.name()); XmlEnumValue annotation = field.getAnnotation(XmlEnumValue.class); if ((annotation != null && annotation.value().equals(inputValue)) || enumVal.name().equals(inputValue)) { return enumVal; } } catch (NoSuchFieldException e) { // 忽略异常,继续匹配 } } throw new IllegalArgumentException("Invalid enum value: " + inputValue); } }
然后注册到Jackson的ObjectMapper:
ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(Enum.class, new JaxbEnumSerializer()); module.addDeserializer(Enum.class, new JaxbEnumDeserializer()); mapper.registerModule(module);
最后把这个ObjectMapper配置到RestEASY的JacksonJsonProvider中即可。
方案4:手动修改生成的枚举类(不推荐)
如果是临时测试或小型项目,可以手动给生成的枚举加Jackson注解:
@XmlEnum public enum YourEnum { @XmlEnumValue("VALUE_1") VALUE_1, @XmlEnumValue("VALUE_2") VALUE_2; @JsonValue public String getValue() { try { return this.getClass().getField(this.name()) .getAnnotation(XmlEnumValue.class).value(); } catch (NoSuchFieldException e) { return this.name(); } } @JsonCreator public static YourEnum fromValue(String value) { for (YourEnum e : values()) { if (e.getValue().equals(value)) { return e; } } throw new IllegalArgumentException("Invalid value: " + value); } }
但注意:每次重新生成代码都会覆盖修改,只适合临时场景。
内容的提问来源于stack exchange,提问作者Inquisitor Shm
相关产品推荐
相关产品推荐

