jmi*_*nez 22 java xml enums jaxb xml-serialization
对于我正在进行的项目,我们使用了很多枚举.模型对象本身由许多小类组成; 然后,我们通过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;
}
}
Run Code Online (Sandbox Code Playgroud)
目前,当序列化为XML时,我们得到类似的东西:
<qualifier>FOO</qualifier>
Run Code Online (Sandbox Code Playgroud)
这是JAXB处理它的方式.但是,我们需要将值作为getCode()的返回值,并且我们的许多枚举都遵循该约定(使用相应的静态方法通过代码进行查找),因此上面的XML片段如下所示:
<qualifier>1E</qualifier>
Run Code Online (Sandbox Code Playgroud)
代替.我们可以对它进行注释@XmlEnum和@XmlEnumValue,但是这太乏味-一些枚举有多达30个枚举值,和手动编辑这是不好的.我们也在考虑使用自定义序列化器,但我现在想避免走那条路(但如果这是要走的路,那么我没问题).
有什么想法?
ska*_*man 24
尝试使用此XmlAdapter机制.您XmlAdapter为每个枚举类型创建一个子类,并且知道如何将枚举编组/解组到XML和从XML解组.
然后,您将适配器与属性相关联,例如
public class QualifierAdapter extends XmlAdapter<String, Qualifier> {
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
}
}
Run Code Online (Sandbox Code Playgroud)
然后在模型类中:
@XmlJavaTypeAdapter(QualifierAdapter.class)
private Qualifier qualifier;
Run Code Online (Sandbox Code Playgroud)
您还可以在包级别,在package-info.java与模型类相同的包中调用的文件中,使用相当特殊的包注释声明:
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters({
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(
type=Qualifier.class, value=QualifierAdapter.class
)
})
package com.xyz;
Run Code Online (Sandbox Code Playgroud)
在寻找其他问题时发现了这个问题,但我读了您对更通用的问题的评论。这是我一直在使用的将大写枚举类型转换为驼峰式的方法。我将使用您的enum类型,但将适配器放在上面。如您所见,您不必引用每个Qualifier实例,而只需注释枚举本身即可。
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<Qualifier> {
public Adapter() {
super(Qualifier.class, FOO);
}
}
}
Run Code Online (Sandbox Code Playgroud)
public abstract class CamelCaseEnumAdapter<E extends Enum> extends XmlAdapter<String, E>{
private Class<E> clazz;
private E defaultValue;
public CamelCaseEnumAdapter(Class<E> clazz) {
this(clazz, null);
}
public CamelCaseEnumAdapter(Class<E> 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("([a-z])([A-Z])", "$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();
}
}
Run Code Online (Sandbox Code Playgroud)