Tutorial :Java/JAXB: Unmarshall XML attributes to specific Java object attributes


There's ugly XML file that has to be unmarshalled:

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

Resulting Java Objects should be:

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

This question's answer is very close but I can't figure out the final solution.


How about?

Introduce a common super class called Options:

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

Then on your class with the list of options (Configuration in this example), specify an @XmlJavaTypeAdapter on that property:

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

The XmlAdapter will look something like this:

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

AdaptedOptions looks like:

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


You may create a separate classes to represent structure of your 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;  }  

and then use an XmlAdapter to perform conversion:

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

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Next Post »