2011-01-11 69 views
18

對於我正在開發的項目,我們有很多枚舉正在使用中。模型對象本身由很多小類組成;這個模型然後通過JAXB作爲XML序列化到我們的數據庫。現在,我們希望能夠使用enum中特定方法的返回來序列化枚舉值;是給予:通過JAXB爲枚舉提供自定義值序列化

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,我們得到這樣的:

<qualifier>FOO</qualifier> 

這是JAXB如何處理它。但是,我們需要將值作爲getCode()的返回值,並且我們的很多枚舉遵循該約定(通過代碼查找相應的靜態方法),以便上面的XML片段看起來像:

<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文件中,使用相當特質包註釋:

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

嗯......這個好像我們要找的人。我的問題實際上是它不夠普遍(不能在enum上使用泛型),但這是可行的。最好爲每個枚舉創建一個適配器,而不是自己註釋枚舉值。謝謝! – jmibanez 2011-01-11 14:20:40

2

發現了這個問題,同時尋找其他的東西,但我看了你的是更爲通用的評論。下面是我用來將大寫枚舉類型轉換爲駱駝案例。我打算使用您的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); 
     } 
    } 
} 


適配器

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(); 
    } 
}