我有一个带有“id”sring 字段和 java.util.Properties 字段及其 getter 和 setter 的 Java 类。如何使用 JAXB 将此类的实例转换为 XML?
非常感谢!
由于 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 元素包裹在整个属性集上时,它似乎也更灵活.
JAXB 可以处理集合,但地图本身并不是集合。而作为集合最合理的表示map的entry set有两个问题:它的元素类型是interface Map.Entry
,不支持通过add
方法修改。前一个问题可以通过适配器规避,但后者使得依赖 JAXB 处理集合变得相当成问题。
可以使用自定义集合类来完成。如果您不想编写自己的集合,那么我建议您使用 anXmlAdapter
创建整个Properties
对象的替代表示。如果您愿意,您可以将其设计为对Properties.storeToXML
and使用的 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
序列化,并实现您自己的集合来封装属性。