java 通过 JAXB 为枚举提供自定义值序列化
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4656992/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Providing custom value serialization for enums via JAXB
提问by jmibanez
For a project I'm working on, we have a lot of enums in use. The model object itself is composed from a lot of tiny classes; this model we then serialize to our DB as XML via JAXB. Now, we want to be able to serialize our enum values using the return of a particular method in the enum; that is given:
对于我正在处理的一个项目,我们使用了很多枚举。模型对象本身由许多小类组成;然后我们通过 JAXB 将此模型作为 XML 序列化到我们的数据库。现在,我们希望能够使用枚举中特定方法的返回来序列化我们的枚举值;给出:
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;
}
}
etc. etc. Currently, when serialized to XML, we get something like:
等等等等。目前,当序列化为 XML 时,我们会得到类似的信息:
<qualifier>FOO</qualifier>
which is how JAXB handles it. However, we need the value to be the return of getCode(), and a whole lot of our enums do follow that convention (with a corresponding static method for lookup via code), so that the above XML fragment looks like:
这就是 JAXB 处理它的方式。然而,我们需要该值是 getCode() 的返回值,并且我们的大量枚举确实遵循该约定(具有用于通过代码查找的相应静态方法),因此上述 XML 片段如下所示:
<qualifier>1E</qualifier>
instead. We can annotate it with @XmlEnum
and @XmlEnumValue
, but that's too tedious -- some enums have up to 30 enumerated values, and hand-editing it is not good. We're also thinking of using a custom serializer instead, but I'd like to avoid going that route for now (but if that's the way to go, then I have no problem with it).
反而。我们可以用@XmlEnum
and注释它@XmlEnumValue
,但这太乏味了——有些枚举有多达 30 个枚举值,手动编辑它并不好。我们也在考虑使用自定义序列化程序,但我现在不想走这条路(但如果这是要走的路,那么我没有问题)。
Any ideas how?
任何想法如何?
回答by skaffman
Try using the XmlAdapter
mechanism for this. You create an XmlAdapter
subclass for each enum type, and which knows how to marshal/unmarshal the enum to and from XML.
尝试XmlAdapter
为此使用该机制。您XmlAdapter
为每个枚举类型创建一个子类,它知道如何将枚举编组/解组到 XML 和从 XML 编组。
You then associate the adapter with the property, e.g.
然后您将适配器与属性相关联,例如
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
}
}
and then in the model classes:
然后在模型类中:
@XmlJavaTypeAdapter(QualifierAdapter.class)
private Qualifier qualifier;
You can also declare this at the package level, inside a file called package-info.java
in the same package as your model classes, using the rather idiosyncratic package annotations:
您还可以在包级别声明这一点,package-info.java
在与模型类相同的包中调用的文件中,使用相当特殊的包注释:
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters({
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(
type=Qualifier.class, value=QualifierAdapter.class
)
})
package com.xyz;
回答by ug_
Found this question while looking for something else but I read your comment about something more generic. Heres what I have been using to convert upper case enum types to camel case. I am going to use your enum
type but put my adapter on it. As you can see you dont need to reference every instance of Qualifier but just annotate the enum itself.
在寻找其他东西时发现了这个问题,但我阅读了您对更通用的东西的评论。下面是我用来将大写枚举类型转换为驼峰大小写的方法。我打算用你的enum
类型,但把我的适配器放在上面。如您所见,您不需要引用 Qualifier 的每个实例,而只需注释枚举本身。
The CamelCaseEnumAdapter can take any enum
however the enum
class must be passed to it therefore you need to have a class extend it, I just use a private static class inside the enum itself.
CamelCaseEnumAdapter 可以接受任何enum
但是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);
}
}
}
Adapter适配器
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])", "_").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();
}
}