Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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.

like image 281
Artyom Sokolov Avatar asked Jul 19 '10 20:07

Artyom Sokolov


1 Answers

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;     }  } 
like image 200
bdoughan Avatar answered Oct 07 '22 12:10

bdoughan