2010-07-19 31 views
19

C'è file XML brutto che deve essere deserializzati:Java/JAXB: attributi XML unmarshall per oggetto Java specifici attributi

<?xml version="1.0" ?> 
<configuration> 
    <section name="default_options"> 
     <value name="default_port">8081</value> 
     <value name="log_level">WARNING</value> 
    </section> 
    <section name="custom_options"> 
     <value name="memory">64M</value> 
     <value name="compatibility">yes</value> 
    </section> 
</configuration> 

risultanti oggetti Java dovrebbero essere: risposta

public class DefaultOptions { 
    private int defaultPort; 
    private String logLevel; 
    // etc... 
} 

public class CustomOptions { 
    private String memory; 
    private String compatibility; 
    // etc... 
} 

This di domanda è molto vicino ma non riesco a capire la soluzione finale.

+0

Non è possibile modificare gli oggetti java risultanti? IMHO sarebbe molto più semplice e pulito se hai appena seguito la struttura xml (o la cambi per seguire la struttura che vuoi) –

+0

@Diego Dias, in realtà no. Ci devono essere POJO come questi. –

+0

È possibile aggiungere una super classe comune a DefaultOptions e CustomOptions? –

risposta

16

ne dite?

introdurre un super-classe comune denominata Opzioni:

import javax.xml.bind.annotation.XmlAttribute; 

public abstract class Options { 

    private String name; 

    @XmlAttribute 
    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

} 

Poi la classe con l'elenco delle opzioni di configurazione (in questo esempio), specificano un @XmlJavaTypeAdapter su quella proprietà:

import java.util.ArrayList; 
import java.util.List; 

import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 

@XmlRootElement 
public class Configuration { 

    private List<Options> section = new ArrayList<Options>(); 

    @XmlJavaTypeAdapter(OptionsAdapter.class) 
    public List<Options> getSection() { 
     return section; 
    } 

    public void setSection(List<Options> section) { 
     this.section = section; 
    } 

} 

XmlAdapter sarà simile al seguente:

import javax.xml.bind.annotation.adapters.XmlAdapter; 

public class OptionsAdapter extends XmlAdapter<AdaptedOptions, Options> { 

    @Override 
    public Options unmarshal(AdaptedOptions v) throws Exception { 
     if("default_options".equals(v.name)) { 
      DefaultOptions options = new DefaultOptions(); 
      options.setName(v.getName()); 
      options.setDefaultPort(Integer.valueOf(v.map.get("default_port"))); 
      options.setLogLevel(v.map.get("log_level")); 
      return options; 
     } else { 
      CustomOptions options = new CustomOptions(); 
      options.setName(v.getName()); 
      options.setCompatibility(v.map.get("compatibility")); 
      options.setMemory(v.map.get("memory")); 
      return options; 
     } 
    } 

    @Override 
    public AdaptedOptions marshal(Options v) throws Exception { 
     AdaptedOptions adaptedOptions = new AdaptedOptions(); 
     adaptedOptions.setName(v.getName()); 
     if(DefaultOptions.class == v.getClass()) { 
      DefaultOptions options = (DefaultOptions) v; 
      adaptedOptions.map.put("default_port", String.valueOf(options.getDefaultPort())); 
      adaptedOptions.map.put("log_level", options.getLogLevel()); 
     } else { 
      CustomOptions options = (CustomOptions) v; 
      adaptedOptions.map.put("compatibility", options.getCompatibility()); 
      adaptedOptions.map.put("memory", options.getMemory()); 
     } 
     return adaptedOptions; 
    } 

} 

AdaptedOption s:

import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
import java.util.Map.Entry; 

import javax.xml.bind.Marshaller; 
import javax.xml.bind.Unmarshaller; 
import javax.xml.bind.annotation.XmlAttribute; 
import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlValue; 

public class AdaptedOptions extends Options { 

    @XmlAttribute String name; 
    @XmlElement List<Value> value = new ArrayList<Value>(); 
    Map<String, String> map = new HashMap<String, String>(); 

    public void beforeMarshal(Marshaller marshaller) { 
     for(Entry<String, String> entry : map.entrySet()) { 
      Value aValue = new Value(); 
      aValue.name = entry.getKey(); 
      aValue.value = entry.getValue(); 
      value.add(aValue); 
     } 
    } 

    public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) { 
     for(Value aValue : value) { 
      map.put(aValue.name, aValue.value); 
     } 
    } 

    private static class Value { 
     @XmlAttribute String name; 
     @XmlValue String value; 
    } 

} 
8

è possibile creare un classi separate per rappresentare la struttura del vostro XML:

public class Section { 
    @XmlAttribute 
    public String name; 
    @XmlElement(name = "value") 
    public List<Value> values; 
} 

public class Value { 
    @XmlAttribute 
    public String name; 
    @XmlValue 
    public String value; 
} 

e quindi utilizzare un XmlAdapter per eseguire la conversione:

public class OptionsAdapter extends XmlAdapter<Section, Options> { 
    public Options unmarshal(Section s) { 
     if ("default_options".equals(s.name)) { 
      ... 
     } else if (...) { 
      ... 
     } 
     ... 
    } 
    ... 
} 

@XmlElement 
public class Configuration { 
    @XmlElement(name = "section") 
    @XmlJavaTypeAdapter(OptionsAdapter.class) 
    public List<Options> options; 
} 

public class DefaultOptions extends Options { ... } 
public class CustomOptions extends Options { ... } 
+0

Soluzione interessante. Prima di tutto, grazie. Lo proverò. È l'unico modo per risolvere il problema? O forse ci sono soluzioni un po 'più eleganti senza "if (" default_options ".equals (s.name))"? –

+0

@Artyom: Poiché JAXB non può dedurre la classe di destinazione dal valore dell'attributo, richiede comunque una sorta di dipatching manuale. Certo, puoi farlo in modo più astratto, ad es. utilizzare una mappa dai valori degli attributi alle fabbriche di opzioni. – axtavt

Problemi correlati