Java / JAXB:将XML属性解组为特定的Java对象属性

有一个丑陋的XML文件必须是unmarshalled:

  
8081 WARNING
64M yes

生成的Java对象应该是:

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

这个问题的答案非常接近,但我无法弄清楚最终的解决方案。

怎么样?

介绍一个名为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; } } 

然后在包含选项列表的类(本示例中为Configuration)中,在该属性上指定@XmlJavaTypeAdapter:

 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 section = new ArrayList(); @XmlJavaTypeAdapter(OptionsAdapter.class) public List getSection() { return section; } public void setSection(List section) { this.section = section; } } 

XmlAdapter看起来像这样:

 import javax.xml.bind.annotation.adapters.XmlAdapter; public class OptionsAdapter extends XmlAdapter { @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看起来像:

 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 = new ArrayList(); Map map = new HashMap(); public void beforeMarshal(Marshaller marshaller) { for(Entry 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; } } 

您可以创建一个单独的类来表示XML的结构:

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

然后使用XmlAdapter执行转换:

 public class OptionsAdapter extends XmlAdapter { 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; } public class DefaultOptions extends Options { ... } public class CustomOptions extends Options { ... }