通过JAXB为枚举提供自定义值序列化

对于我正在进行的项目,我们使用了很多枚举。 模型对象本身由许多小类组成; 然后,我们通过JAXB将此模型作为XML序列化到我们的DB。 现在,我们希望能够使用枚举中特定方法的返回来序列化我们的枚举值; 给出的:

public enum Qualifier { FOO("1E", "Foo type document"), BAR("2", "Bar object"); private String code, description; public Qualifier(String code, String description) { this.code = code; this.description = description; } public String getCode() { return this.code; } public String getDescription() { return this.description; } } 

目前,当序列化为XML时,我们得到类似的东西:

 FOO 

这是JAXB处理它的方式。 但是,我们需要将值作为getCode()的返回值,并且我们的许多枚举都遵循该约定(使用相应的静态方法通过代码进行查找),因此上面的XML片段如下所示:

 1E 

代替。 我们可以使用@XmlEnum@XmlEnumValue来注释它,但这太繁琐了 – 一些枚举最多有30个枚举值,手动编辑它并不好。 我们也在考虑使用自定义序列化程序,但我现在想避免使用这条路径(但如果这是要走的路,那么我没有问题)。

有什么想法?

尝试使用XmlAdapter机制。 您为每个枚举类型创建一个XmlAdapter子类,它知道如何编组/解组枚举到XML和从XML解组。

然后,您将适配器与属性相关联,例如

 public class QualifierAdapter extends XmlAdapter { public String marshal(Qualifier qualifier) { return qualifier.getCode(); } public Qualifier unmarshal(String val) { return Qualifier.getFromCode(val); // I assume you have a way of doing this } } 

然后在模型类中:

 @XmlJavaTypeAdapter(QualifierAdapter.class) private Qualifier qualifier; 

您还可以在包级别,在与模型类相同的包中名为package-info.java的文件中,使用相当特殊的包注释声明:

 @javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters({ @javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter( type=Qualifier.class, value=QualifierAdapter.class ) }) package com.xyz; 

在寻找其他东西时发现了这个问题,但我读到了关于更通用的东西的评论。 下面是我用来将大写枚举类型转换为驼峰大小写的内容。 我将使用你的enum类型,但把我的适配器放在它上面。 如您所见,您不需要引用限定符的每个实例,只需注释枚举本身。

CamelCaseEnumAdapter可以接受任何enum但是必须将enum类传递给它,因此你需要有一个类扩展它,我只是在枚举本身内部使用私有静态类。


枚举:

 @XmlJavaTypeAdapter(Qualifier.Adapter.class) public enum Qualifier { FOO("1E", "Foo type document"), BAR("2", "Bar object"); private String code, description; public Qualifier(String code, String description) { this.code = code; this.description = description; } public String getCode() { return this.code; } public String getDescription() { return this.description; } private static class Adapter extends CamelCaseEnumAdapter { public Adapter() { super(Qualifier.class, FOO); } } } 

适配器

 public abstract class CamelCaseEnumAdapter extends XmlAdapter{ private Class clazz; private E defaultValue; public CamelCaseEnumAdapter(Class clazz) { this(clazz, null); } public CamelCaseEnumAdapter(Class clazz, E defaultValue) { this.clazz = clazz; this.defaultValue = defaultValue; } @Override @SuppressWarnings("unchecked") public E unmarshal(String v) throws Exception { if(v == null || v.isEmpty()) return defaultValue; return (E) Enum.valueOf(clazz, v.replaceAll("([az])([AZ])", "$1_$2").toUpperCase()); } @Override public String marshal(E v) throws Exception { if(v == defaultValue) return null; return toCamelCase(v.name()); } private String toCamelCase(String s){ String[] parts = s.split("_"); String camelCaseString = ""; for (String part : parts){ if(camelCaseString.isEmpty()) camelCaseString = camelCaseString + part.toLowerCase(); else camelCaseString = camelCaseString + toProperCase(part); } return camelCaseString; } private String toProperCase(String s) { return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); } }