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:
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:
<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:
<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).
Any ideas how?
To serialize an enum constant, ObjectOutputStream writes the value returned by the enum constant's name method. To deserialize an enum constant, ObjectInputStream reads the constant name from the stream; the deserialized constant is then obtained by calling the java.
Because enums are automatically Serializable (see Javadoc API documentation for Enum), there is no need to explicitly add the "implements Serializable" clause following the enum declaration. Once this is removed, the import statement for the java. io.
You can assign different values to enum member. A change in the default value of an enum member will automatically assign incremental values to the other members sequentially.
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.
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:
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters({ @javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter( type=Qualifier.class, value=QualifierAdapter.class ) }) package com.xyz;
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.
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.
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); } } }
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(); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With