有一个丑陋的 XML 文件需要解码:
<?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>
生成的 Java 对象应该是:
public class DefaultOptions {
private int defaultPort;
private String logLevel;
// etc...
}
public class CustomOptions {
private String memory;
private String compatibility;
// etc...
}
This问题的答案非常接近,但我无法弄清楚最终的解决方案。
最佳答案
怎么样?
引入一个通用的父类(super class),叫做 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;
}
}
然后在带有选项列表的类(本例中的配置)上,在该属性上指定一个 @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<Options> section = new ArrayList<Options>();
@XmlJavaTypeAdapter(OptionsAdapter.class)
public List<Options> getSection() {
return section;
}
public void setSection(List<Options> section) {
this.section = section;
}
}
XmlAdapter 看起来像这样:
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 看起来像:
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;
}
}
关于Java/JAXB : Unmarshall XML attributes to specific Java object attributes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3284786/