Java/JAXB: немаршальские атрибуты XML к определенным атрибутам объектов Java

Существует ужасный XML-файл, который должен быть не упорядочен:



    
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...
}

Ответ этого вопроса очень близок, но я не могу выяснить конечное решение.

19
задан Community 23 May 2017 в 12:17
поделиться

2 ответа

Как насчет?

Представьте общий суперкласс с именем 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<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;
    }

}
19
ответ дан 30 November 2019 в 04:20
поделиться

Вы можете создать отдельные классы для представления структуры вашего 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 { ... }
8
ответ дан 30 November 2019 в 04:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: