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);