2011-01-11 9 views
18

私が取り組んでいるプロジェクトでは、多くのenumが使用されています。モデルオブジェクト自体は、多くの小さなクラスから構成されています。このモデルをJAXBを介してXMLとしてXML DBに直列化します。ここでは、列挙型の特定のメソッドの戻り値を使用して列挙型の値をシリアル化できるようにしたいと考えています。それが与えられます。JAXB経由でenumのカスタム値のシリアル化を提供

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にシリアライズするとき、現在、私たちのようなものを得る:JAXBはそれをどのように処理するかである

<qualifier>FOO</qualifier> 

を。しかし、getCode()の戻り値が必要であり、多くのenumがその規約に従っています(コードによるルックアップの静的メソッドに対応)。

<qualifier>1E</qualifier> 

代わりに。 @XmlEnum@XmlEnumValueと注釈を付けることができますが、それはあまりにも面倒です - いくつかの列挙型には最大30の列挙値があり、手動編集は良くありません。代わりにカスタムシリアライザを使用することも考えていますが、今はそのルートには行かないようにしたいと思います(ただし、これが問題になる場合は問題ありません)。

どのようにすればいいですか?

答えて

19

これにはXmlAdapterメカニズムを使用してみてください。列挙型ごとにXmlAdapterサブクラスを作成し、列挙型を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 
    } 
} 

、その後、モデルクラスに:

@XmlJavaTypeAdapter(QualifierAdapter.class) 
private Qualifier qualifier; 

また、かなり特異なパッケージを使用して、あなたのモデルクラスと同じパッケージでpackage-info.javaと呼ばれるファイル内で、パッケージレベルでこれを宣言することができます注釈:

+1

うーん...これは我々が探しているもののように見えます。私の問題は実際には一般的ではないことです(列挙型のジェネリックは使用できません)が、それは実行可能です。列挙型の値に注釈を付けるのではなく、列挙型ごとにアダプタを1つ作成する方が良いでしょう。ありがとう! – jmibanez

2

何か他のものを探しているときにこの質問が見つかりましたが、より一般的なものについてのあなたのコメントを読んでいます。私が大文字の列挙型をキャメルケースに変換するために使ってきたことenumタイプを使用しますが、アダプタを取り付けます。ご覧のとおり、修飾子のすべてのインスタンスを参照する必要はありませんが、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<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(); 
    } 
} 
関連する問題