JAXB

2011-01-11 21 views
18

के माध्यम से enums के लिए कस्टम मान क्रमबद्धता प्रदान करना एक परियोजना के लिए मैं काम कर रहा हूं, हमारे पास उपयोग में बहुत सारे enums हैं। मॉडल ऑब्जेक्ट स्वयं बहुत छोटी कक्षाओं से बना है; इस मॉडल के बाद हम जेएक्सबी के माध्यम से एक्सएम के रूप में हमारे डीबी को क्रमबद्ध करते हैं। अब, हम enum में एक विशेष विधि की वापसी का उपयोग कर हमारे 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; 
    } 
} 

आदि आदि वर्तमान में, जब एक्सएमएल के लिए धारावाहिक, हम की तरह कुछ मिलता है:

<qualifier>FOO</qualifier> 

जो है कैसे JAXB यह संभालती है। हालांकि, हमें getCode() की वापसी होने के लिए मूल्य की आवश्यकता है, और हमारे बहुत सारे enums इस सम्मेलन का पालन करते हैं (कोड के माध्यम से लुकअप के लिए एक समान स्थैतिक विधि के साथ), ताकि उपर्युक्त एक्सएमएल खंड इस तरह दिखता है:

<qualifier>1E</qualifier> 

इसके बजाए। हम इसे @XmlEnum और @XmlEnumValue के साथ एनोटेट कर सकते हैं, लेकिन यह बहुत कठिन है - कुछ enums के पास 30 अंकित मान हैं, और हाथ-संपादन यह अच्छा नहीं है। हम इसके बजाय एक कस्टम सीरियलाइज़र का उपयोग करने के बारे में भी सोच रहे हैं, लेकिन मैं अभी उस मार्ग पर जाने से बचना चाहता हूं (लेकिन अगर यह जाने का रास्ता है, तो मुझे इसके साथ कोई समस्या नहीं है)।

कोई विचार कैसे?

उत्तर

19

इसके लिए XmlAdapter तंत्र का उपयोग करने का प्रयास करें। आप प्रत्येक enum प्रकार के लिए XmlAdapter उप-वर्ग बनाते हैं, और जो जानता है कि XML से और उसके लिए enumshal enumshal कैसे करें।

फिर आप एडाप्टर को संपत्ति के साथ जोड़ते हैं, उदा।

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 पर जेनेरिक का उपयोग नहीं कर सकते), लेकिन यह काम करने योग्य है।Enum मूल्यों को एनोटेट करने के बजाए प्रति एडमेटर प्रति एनम बनाना बेहतर होगा। धन्यवाद! – jmibanez

2

कुछ और ढूंढते समय यह प्रश्न मिला लेकिन मैंने कुछ और सामान्य के बारे में आपकी टिप्पणी पढ़ी। ऊपरी केस एनम प्रकारों को ऊंट के मामले में बदलने के लिए मैं क्या उपयोग कर रहा हूं। मैं आपके enum प्रकार का उपयोग करने जा रहा हूं लेकिन मेरे एडाप्टर को उस पर डाल दूंगा। जैसा कि आप देख सकते हैं कि आपको क्वालीफायर के प्रत्येक उदाहरण को संदर्भित करने की आवश्यकता नहीं है, बल्कि केवल enum को एनोटेट करें।

CamelCaseEnumAdapter ले जा सकते हैं किसी भी enum तथापि 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); 
     } 
    } 
} 


एडाप्टर

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