マーシャリングを解除する必要がある醜い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 質問の答えは非常に近いですが、最終的な解決策がわかりません。
どうですか?
オプションと呼ばれる一般的なスーパークラスを導入します。
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;
}
}
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;
}
次に、XmlAdapter
を使用して変換を実行します。
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 { ... }