JAXB

2011-01-11 28 views
18

aracılığıyla enumlar için özel değer serileştirmesi sağlama Üzerinde çalıştığım bir proje için, kullanımda çok fazla sayıda kaynağımız var. Model nesnenin kendisi çok küçük sınıflardan oluşur; Bu model daha sonra DB olarak XML olarak JAXB ile serileştiriyoruz. Şimdi, enum değerlerimizi, enumdaki belirli bir yöntemin geri dönüşünü kullanarak serileştirmek istiyoruz; O verilir: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; 
    } 
} 

vs vs XML tefrika Şu anda, biz böyle bir şey olsun: JAXB bunu nasıl işleyeceğini ise

<qualifier>FOO</qualifier> 

. Ancak, getCode() dönüş olmak değeri gerekir ve yukarıdaki XML parçası görünüyor ki bizim çeteleler bir sürü, (kodu aracılığıyla arama için karşılık gelen bir statik yöntemle) o uylaşımını yaptığı gibi:

Bunun yerine,
<qualifier>1E</qualifier> 

. @XmlEnum ve @XmlEnumValue ile açıklama ekleyebiliriz, ancak bu çok sıkıcıdır - bazı numaralar 30'a kadar numaralandırılmış değerlere sahiptir ve el ile düzenleme iyi değildir. Bunun yerine özel bir seri hale getirici kullanmayı düşünüyoruz, ancak şu an bu rotayı sürdürmekten kaçınmak istiyorum (ama eğer bu şekilde giderse, o zaman bununla bir sorunum yok).

Herhangi bir fikir nasıl?

cevap

19

Bunun için XmlAdapter mekanizmasını kullanmayı deneyin. Her enum türü için bir XmlAdapter alt sınıfı oluşturuyorsunuz ve XML'ye ve XML'den enumuzu nasıl sıralayacağınızı/marifetleyeceğinizi biliyorsunuz.

Bağdaştırıcıyla özelliği ilişkilendirirsiniz, ör. Model sınıflarında

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 
    } 
} 

ve sonra:

@XmlJavaTypeAdapter(QualifierAdapter.class) 
private Qualifier qualifier; 
Ayrıca oldukça kendine has bir paket kullanarak, modeliniz sınıfları aynı pakette package-info.java adlı bir dosya içindeki, paket düzeyinde bu ilan edebilir

ek açıklamalar: başka bir şey ararken

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

Hmm ... Bu bizim aradığımız benziyor

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


Adaptör. Sorunum gerçekten (enum üzerinde jenerikleri kullanamazsınız) yeterince genel olmadığını, ama bu işe yarar bu.Enum değerlerinin kendilerine açıklama eklemek yerine enum başına bir bağdaştırıcı oluşturmak daha iyi olacaktır. Teşekkürler! – jmibanez

2

bu soruyu bulundu ama daha genel bir konuda sizin yorumunuzu. Büyük harf enum türlerini deve durumuna dönüştürmek için kullandığım heres. Ben senin enum tipini kullanacağım ama adaptörümü üzerine koyacağım. Gördüğünüz gibi size Qualifier'ın her örneğini başvuru ama sadece enum kendisi açıklama için gerek yoktur.

CamelCaseEnumAdapter sadece enum kendisi içinde özel statik sınıfını kullanın, enum sınıf kendisine geçmiş olması gerekir ancak herhangi enum nedenle bir sınıf bunu uzatmak olması gerekir alabilir.


Enum:

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