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

后端 未结 2 1837
遥遥无期
遥遥无期 2020-12-01 06:41

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



    
相关标签:
2条回答
  • 2020-12-01 07:16

    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;
        }
    
    }
    
    0 讨论(0)
  • 2020-12-01 07:33

    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 { ... }
    
    0 讨论(0)
提交回复
热议问题