Java 自定义地图<;对象,对象>;XmlAdapter
我正在尝试将Java 自定义地图<;对象,对象>;XmlAdapter,java,map,jaxb,marshalling,Java,Map,Jaxb,Marshalling,我正在尝试将MapXmlAdapter改编为支持Map的。该方法基于本文: JAXBContext jc = JAXBContext.newInstance(Foo.class); 测试线束中的这一行生成NullPointerException: JAXBContext jc = JAXBContext.newInstance(Foo.class); 如果我将线束和MapAdapter/MapEntry更改为T,代码将按预期工作 JAXBContext jc = JAXBContext.ne
Map
XmlAdapter
改编为支持Map
的。该方法基于本文:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
测试线束中的这一行生成NullPointerException
:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
如果我将线束和MapAdapter/MapEntry更改为T
,代码将按预期工作
JAXBContext jc = JAXBContext.newInstance(Foo.class);
我错过了什么?对象
类型是否可以序列化,或者是否需要转换为另一个不太抽象的类?如果是这样,我会认为我会在marshal()
方法中遇到此错误,但它似乎从未达到这一点(至少在Netbean的调试器中)
JAXBContext jc = JAXBContext.newInstance(Foo.class);
MapEntryType:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
public class MyMapEntryType {
@XmlAttribute
public Object key;
@XmlValue
public Object value;
}
public class MyMapEntryType {
@XmlAttribute
public String key;
@XmlValue
public String value;
private MyMapEntryType() {
//Required by JAXB
}
public MyMapEntryType(String key, String value) {
this.key = key;
this.value = value;
}
}
地图类型:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
public class MyMapType {
public List<MyMapEntryType> entry = new ArrayList<MyMapEntryType>();
}
但是,尝试封送此条目时:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
xyz.put("key0", 1);
导致一个错误,内容如下:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
unable to marshal type `java.lang.Integer` as an element because it is missing an `@XmlRootElement` annotation
我只是随便看看,才发现。因此,您可以使用自定义XMLDOM转换器使用
@xmlanyement
,或者您需要使用@xmlementrefs
显式指定此属性的可能类。我可以通过内部使用映射来解决此问题:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
MyMapEntryType:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
public class MyMapEntryType {
@XmlAttribute
public Object key;
@XmlValue
public Object value;
}
public class MyMapEntryType {
@XmlAttribute
public String key;
@XmlValue
public String value;
private MyMapEntryType() {
//Required by JAXB
}
public MyMapEntryType(String key, String value) {
this.key = key;
this.value = value;
}
}
MyMapType类:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
public class MyMapType {
@XmlElement(name="Property")
public List<MyMapEntryType> entry = new ArrayList<MyMapEntryType>();
}
public class MyMapAdapter extends XmlAdapter<MyMapType, Map<String,Object>> {
@Override
public MyMapType marshal(Map<String,Object> bt) throws Exception {
MyMapType myMapType = new MyMapType();
for(Map.Entry<String,Object> entry : bt.entrySet()) {
MyMapEntryType myMapEntryType = new MyMapEntryType(entry.getKey(), entry.getValue().toString());
myMapType.entry.add(myMapEntryType);
}
return myMapType;
}
...
}
公共类MyMapType{
@xmlement(name=“Property”)
public List entry=new ArrayList();
}
公共类MyMapAdapter扩展了XmlAdapter{
@凌驾
公共MyMapType封送处理(Map bt)引发异常{
MyMapType MyMapType=新的MyMapType();
for(Map.Entry:bt.entrySet()){
MyMapEntryType MyMapEntryType=新的MyMapEntryType(entry.getKey(),entry.getValue().toString());
myMapType.entry.add(myMapEntryType);
}
返回myMapType;
}
...
}
PropertyBag(nee-Foo)类别:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
@XmlRootElement(name=“PropertyBag”)
公共类PropertyBag{
私人地图;
公共财产bag(){
map=新的HashMap();
}
@XmlJavaTypeAdapter(MyMapAdapter.class)
@xmlement(name=“Properties”)
公共地图getMap(){
返回图;
}
公共无效集合映射(映射映射){
this.map=map;
}
}
线束:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
Map<String, Object> parent = new HashMap<String, Object>();
parent.put("SI_EMAIL_ADDRESS", "foo@bar.edu");
parent.put("SI_DATE", new Date());
parent.put("SI_GUID", "ATQJj1RvgVlLqDqP_VOGltM");
parent.put("SI_BOOLEAN", true);
parent.put("SI_INT", 1318);
parent.put("SI_LONG", new Long(123456789));
parent.put("SI_INTEGER", new Integer(23456));
PropertyBag bag = new PropertyBag();
bag.setMap(parent);
JAXBContext jc = JAXBContext.newInstance(PropertyBag.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(bag, System.out);
Map parent=newhashmap();
parent.put(“SI_电子邮件地址”foo@bar.edu");
parent.put(“SI_DATE”,new DATE());
put(“SI_GUID”、“ATQJj1RvgVlLqDqP_VOGltM”);
parent.put(“SI_BOOLEAN”,true);
母公司。put(“SI_INT”,1318);
母公司。put(“斯尤龙”,新龙(123456789));
put(“SI_整数”,新整数(23456));
PropertyBag bag=新的PropertyBag();
bag.setMap(父级);
JAXBContext jc=JAXBContext.newInstance(PropertyBag.class);
Marshaller=jc.createMarshaller();
setProperty(marshaller.JAXB_格式化的_输出,true);
元帅,元帅(包,系统,输出);
输出:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
<PropertyBag>
<Properties>
<Property key="SI_INT">1318</Property>
<Property key="SI_DATE">Wed Feb 01 22:18:35 EST 2012</Property>
<Property key="SI_BOOLEAN">true</Property>
<Property key="SI_LONG">123456789</Property>
<Property key="SI_INTEGER">23456</Property>
<Property key="SI_GUID">ATQJj1RvgVlLqDqP_VOGltM</Property>
<Property key="SI_EMAIL_ADDRESS">foo@bar.edu</Property>
</Properties>
</PropertyBag>
1318
美国东部时间2012年2月1日星期三22:18:35
真的
123456789
23456
ATQJj1RvgVlLqDqP_VOGltM
foo@bar.edu
理想情况下,我希望将XML表示为:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
<Properties>
<SI_INT>1318</SI_INT>
<SI_DATE>Wed Feb 01 22:18:35 EST 2012</SI_DATE>
<SI_BOOLEAN>true</SI_BOOLEAN>
<SI_LONG>123456789</SI_LONG>
<SI_INTEGER>23456</SI_INTEGER>
<SI_GUID>ATQJj1RvgVlLqDqP_VOGltM</SI_GUID>
<SI_EMAIL_ADDRESS>foo@bar.edu</SI_EMAIL_ADDRESS>
</Properties>
1318
美国东部时间2012年2月1日星期三22:18:35
真的
123456789
23456
ATQJj1RvgVlLqDqP_VOGltM
foo@bar.edu
我还希望能够序列化子属性:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
...
Map<String,Object> child = new HashMap<String,Object>();
child.put("1", 33217);
child.put("2", 36351);
child.put("SI_TOTAL", 2);
parent.put("SI_LIST", child);
。。。
Map child=newhashmap();
child.put(“1”,33217);
child.put(“2”,36351);
child.put(“SI_TOTAL”,2);
父项。put(“SI_列表”,子项);
代表将是:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
<Properties>
<SI_INT>1318</SI_INT>
<SI_DATE>Wed Feb 01 22:18:35 EST 2012</SI_DATE>
<SI_BOOLEAN>true</SI_BOOLEAN>
<SI_LONG>123456789</SI_LONG>
<SI_INTEGER>23456</SI_INTEGER>
<SI_GUID>ATQJj1RvgVlLqDqP_VOGltM</SI_GUID>
<SI_EMAIL_ADDRESS>foo@bar.edu</SI_EMAIL_ADDRESS>
<SI_LIST>
<!-- numeric elements are illegal; refactor -->
<1>33217</1>
<2>36351</2>
<SI_TOTAL>2</SI_TOTAL>
</SI_LIST>
</Properties>
1318
美国东部时间2012年2月1日星期三22:18:35
真的
123456789
23456
ATQJj1RvgVlLqDqP_VOGltM
foo@bar.edu
33217
36351
2.
但我不确定是否可以使用注释将键名转换为元素。我可能错了,但我认为JAXB无法进行类型探索。在原始情况下,对象位于
MyMapEntryType
中。数组是对象,映射是对象,原语包装器是对象,任何其他复合类实例都是对象。JAXB如何通过查看此对象来确定要使用的序列化程序?它可以是“公共”类型的内置序列化程序,但未知类型需要链中的另一个适配器。所以,我需要为每个非公共类型提供一个XmlAdapter?是的。已经支持基本类型,如字符串、日期、列表和所有原语,但对于其余类型,您需要以这种或那种方式显式声明如何(反)序列化它们。这里的要点是,JAXB在创建上下文时构建所有类(以及可能的XML映射)的元模型,而不是在完成编组时。对于类型Object
JAXB无法发现可能的马歇尔方法。如果您想隐藏在对象
后面的XML片段是变化的,那么您需要走这条路。非常感谢您的回答。基于此,我能够完成我的XMLAdapter编组方法。然而,我对XmlAdapter
类中的解组方法有点吃惊。您能提供一些关于如何解组类型映射的想法吗?
JAXBContext jc = JAXBContext.newInstance(Foo.class);