JAXB 编组由 XmlAdapter 创建的 ArrayList [英] JAXB marshal an ArrayList created by XmlAdapter
问题描述
我想使用 XmlAdapter
调整 HashMap
字段的 XML 表示.我使用 ArrayList
来做到这一点.但是,在编组 ArrayList
时根本没有编组.这是为什么?
I want to adapt the XML representation of a HashMap
field using XmlAdapter
. I use an ArrayList
to do that. However, when marshalling the ArrayList
is not marshalled at all. Why is that?
代码
@XmlRootElement
public class Foo {
private HashMap<String, String> hashMap;
public Foo() {
this.hashMap = new HashMap<String, String>();
}
@XmlJavaTypeAdapter(HashMapAdapter.class)
public HashMap<String, String> getHashmap() {
return hashMap;
}
public void setHashmap(HashMap<String, String> hashMap) {
this.hashMap = hashMap;
}
}
public final class HashMapAdapter extends XmlAdapter<ArrayList<HashMapEntry>, HashMap<String, String>> {
@Override
public ArrayList<HashMapEntry> marshal(HashMap<String, String> arg0) throws Exception {
ArrayList<HashMapEntry> result = new ArrayList<HashMapEntry>();
for(Entry<String, String> entry : arg0.entrySet())
result.add(new HashMapEntry(entry.getKey(), entry.getValue()));
return result;
}
@Override
public HashMap<String, String> unmarshal(ArrayList<HashMapEntry> arg0) throws Exception {
HashMap<String, String> result = new HashMap<String, String>();
for(HashMapEntry entry : arg0)
result.put(entry.key, entry.value);
return result;
}
}
public class HashMapEntry {
@XmlElement
public String key;
@XmlValue
public String value;
public HashMapEntry() {
}
public HashMapEntry(String key, String value) {
this.key = key;
this.value = value;
}
}
结果
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><foo><hashmap/></foo>
推荐答案
在您的 XmlAdapter
中,您需要将 HashMap
转换为带有 List
属性,而不是直接添加到 ArrayList
.
In your XmlAdapter
you need to convert the HashMap
to an an instance of an object with a List
property instead of directly to an ArrayList
.
HashMapAdapter
package forum13163430;
import java.util.*;
import java.util.Map.Entry;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public final class HashMapAdapter extends XmlAdapter<HashMapAdapter.AdaptedHashMap, HashMap<String, String>> {
@Override
public AdaptedHashMap marshal(HashMap<String, String> hashMap) throws Exception {
AdaptedHashMap adaptedHashMap = new AdaptedHashMap();
for(Entry<String, String> entry : hashMap.entrySet()) {
adaptedHashMap.item.add(new HashMapEntry(entry.getKey(), entry.getValue()));
}
return adaptedHashMap;
}
@Override
public HashMap<String, String> unmarshal(AdaptedHashMap adaptedHashMap) throws Exception {
HashMap<String, String> result = new HashMap<String, String>();
for(HashMapEntry entry : adaptedHashMap.item)
result.put(entry.key, entry.value);
return result;
}
public static class AdaptedHashMap {
public List<HashMapEntry> item = new ArrayList<HashMapEntry>();
}
public static class HashMapEntry {
@XmlAttribute
public String key;
@XmlValue
public String value;
public HashMapEntry() {
}
public HashMapEntry(String key, String value) {
this.key = key;
this.value = value;
}
}
}
了解更多信息
更新
谢谢,这有效.但是后来我得到了一个额外的水平生成的 XML 中的注释.有什么办法可以避免吗?
Thanks, this works. However then I get an additional level of annotation in the produced XML. Is there any way to avoid that?
如果您使用 EclipseLink MOXy 作为您的 <一个 href="http://jcp.org/en/jsr/detail?id=222" rel="nofollow">JAXB (JSR-222) 提供者,然后你就可以利用此用例的 @XmlPath
扩展.下面我用一个例子来演示.
If you are using EclipseLink MOXy as your JAXB (JSR-222) provider then you can leverage the @XmlPath
extension for this use case. I'll demonstrate below with an example.
Foo
在 @XmlJavaTypeAdapter
之外的 hashmap
属性上,我添加了 MOXy 的 @XmlPath
注释."."
的 XML 路径表示应该将子元素编组到父 XML 元素中.
On the hashmap
property in additional to the @XmlJavaTypeAdapter
I have added MOXy's @XmlPath
annotation. An XML path of "."
indicates that the child should be marshalled into the parents XML element.
package forum13163430;
import java.util.HashMap;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.eclipse.persistence.oxm.annotations.XmlPath;
@XmlRootElement
public class Foo {
private HashMap<String, String> hashMap;
public Foo() {
this.hashMap = new HashMap<String, String>();
}
@XmlPath(".")
@XmlJavaTypeAdapter(HashMapAdapter.class)
public HashMap<String, String> getHashmap() {
return hashMap;
}
public void setHashmap(HashMap<String, String> hashMap) {
this.hashMap = hashMap;
}
}
jaxb.properties
要将 MOXy 指定为您的 JAXB 提供程序,您需要在与域模型相同的包中包含一个名为 jaxb.properties
的文件,其中包含以下条目(请参阅:http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).
To specify MOXy as your JAXB provider you need to include a file called jaxb.properties
in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
演示
由于 MOXy 是符合 JAXB (JSR-222) 的实现,因此标准 API 可用于将对象从 XML 转换为 XML.
Since MOXy is JAXB (JSR-222) compliant implementation, the standard APIs can be used to convert objects from/to XML.
package forum13163430;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Foo.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum13163430/input.xml");
Foo foo = (Foo) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(foo, System.out);
}
}
input.xml/输出
以下是运行演示代码的输入和输出.
Below is the input to and output from running the demo code.
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<item key="b">B</item>
<item key="c">C</item>
<item key="a">A</item>
</foo>
了解更多信息
这篇关于JAXB 编组由 XmlAdapter 创建的 ArrayList的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!