3

我有一个带有“id”sring 字段和 java.util.Properties 字段及其 getter 和 setter 的 Java 类。如何使用 JAXB 将此类的实例转换为 XML?

非常感谢!

4

2 回答 2

0

由于 JAXB 显然可以处理集合,但不能处理映射,因此您可以提供自己的属性字段的集合视图,基于AbstractCollection.

@XmlType(name="property") class XmlProperty {
    @XmlAttribute public String key;
    @XmlValue public String value;
}

class XmlProperties extends AbstractCollection<XmlProperty> {
    private final Properties props;
    public XmlProperties(Properties props) { this.props = props; }
    public int size() { return props.size(); }
    public Iterator<XmlProperty> iterator() {
        return new XmlPropertyIterator(props.entrySet().iterator());
    }
    public boolean add(XmlProperty xml) {
        return !xml.value.equals(props.setProperty(xml.key, xml.value));
    }
}

class XmlPropertyIterator implements Iterator<XmlProperty> {
    private final Iterator<Map.Entry<Object, Object>> base;
    public XmlPropertyIterator(Iterator<Map.Entry<Object, Object>> base) {
        this.base = base;
    }
    public boolean hasNext() { return base.hasNext(); }
    public void remove() { base.remove(); }
    public XmlProperty next() {
        Map.Entry<?, ?> entry = base.next();
        XmlProperty xml = new XmlProperty();
        xml.key = entry.getKey().toString();
        xml.value = entry.getValue().toString();
        return xml;
    }
}

您可以让类型的 getterCollection<XmlProperty>返回一个XmlProperties包装您的Properties字段的对象。

我再次提供了这段代码的可执行演示。它有一个像你描述的那样的类,带有一个标识符和一个属性字段。属性字段使用建模

@XmlElement(name="property")
public Collection<XmlProperty> getProperties() {
    return new XmlProperties(props);
}

请注意,Properties集合的各个条目将是代表您的包含类的元素的直接子级。如果这不受欢迎,您可以使用@XmlElementWrapper注释在它们周围提供包装元素。

将此答案与我的第一个答案进行比较,它似乎更有效,因为它一次只转换一个地图条目,而且在您是否希望将 XML 元素包裹在整个属性集上时,它似乎也更灵活.

于 2013-10-22T20:27:02.633 回答
0

JAXB 可以处理集合,但地图本身并不是集合。而作为集合最合理的表示map的entry set有两个问题:它的元素类型是interface Map.Entry,不支持通过add方法修改。前一个问题可以通过适配器规避,但后者使得依赖 JAXB 处理集合变得相当成问题。

可以使用自定义集合类来完成。如果您不想编写自己的集合,那么我建议您使用 anXmlAdapter创建整个Properties对象的替代表示。如果您愿意,您可以将其设计为对Properties.storeToXMLand使用的 XML 方案进行建模Properties.loadFromXML。像这样的东西:

@XmlType(name="property") class XmlProperty {
    @XmlAttribute public String key;
    @XmlValue public String value;
}

@XmlType(name="properties") class XmlProperties {
    @XmlElement(name="entry") public Collection<XmlProperty> entries
        = new ArrayList<XmlProperty>();
}

// for use with a @XmlJavaTypeAdapter(PropertiesAdapter.class) annotation
class PropertiesAdapter extends XmlAdapter<XmlProperties, Properties> {
    public XmlProperties marshal(Properties props) {
        XmlProperties xml = new XmlProperties();
        for (Map.Entry<Object, Object> entry: props.entrySet()) {
            XmlProperty xmlEntry = new XmlProperty();
            xmlEntry.key = entry.getKey().toString();
            xmlEntry.value = entry.getValue().toString();
            xml.entries.add(xmlEntry);
        }
        return xml;
    }
    public Properties unmarshal(XmlProperties xml) {
        Properties props = new Properties();
        for (XmlProperty entry: xml.entries)
            props.setProperty(entry.key, entry.value);
        return props;
    }
}

我还编写了一个小的可执行演示片段,它使用它来序列化你描述的类,除了属性成员之外还有一个 id。访问器是这样写的:

@XmlElement
@XmlJavaTypeAdapter(PropertiesAdapter.class)
public Properties getProperties() { return props; }
public void setProperties(Properties props) { this.props.putAll(props); }

请注意,整个Properties字段被序列化为单个 <properties>元素,该元素又包含任意数量的<entry>元素。如果您希望将条目作为类元素的直接子元素,那么您必须依赖Collection序列化,并实现您自己的集合来封装属性。

于 2013-10-22T20:09:06.190 回答