2

List<Map<String,Object>>のインスタンスをXML で次のように表現したいと思います。

<row>
   <entry key="key1" xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">value1</entry>
   <entry key="key2" xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">value2</entry>
   <entry key="key3" />
   <entry key="keyDate" xsi:type="xs:dateTime" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">2012-08-19T13:00:59.412-04:00</entry>
</row>

ここでkey1、 とkey2は文字列、key3は nil、keyDateは日付です。

の次の実装を使用して、これに近づくことができますXmlAdapter

package net.parkerson.test1;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class JAXBMapAdapter extends XmlAdapter<JAXBMapAdapter.JAXBMap, Map<String, Object>>
{

    @Override
    public JAXBMap marshal(Map<String, Object> map) throws Exception
    {
        JAXBMap jaxbMap = new JAXBMap();
        for (Entry<String, Object> entry : map.entrySet())
        {
            jaxbMap.entry.add(new JAXBMapEntry(entry));
        }
        return jaxbMap;

    }

    @Override
    public Map<String, Object> unmarshal(JAXBMapAdapter.JAXBMap mappedObject) throws Exception
    {
        HashMap<String, Object> map = new HashMap<String, Object>();
        for (JAXBMapEntry entry : mappedObject.entry)
        {
            map.put(entry.key, entry.value);
        }
        return map;
    }

    public static class JAXBMapEntry
    {

        @XmlAttribute
        public String key;

        @XmlElement
        public Object value;

        public JAXBMapEntry()
        {
        }

        public JAXBMapEntry(Map.Entry<String, Object> entry)
        {
            key = entry.getKey();
            value = entry.getValue();
        }
    }

    public static class JAXBMap
    {
        public List<JAXBMapAdapter.JAXBMapEntry> entry = new ArrayList<JAXBMapAdapter.JAXBMapEntry>();
    }
}

および次のテスト コード:

package net.parkerson.test1;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXB;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElements;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import net.parkerson.test1.JAXBMapAdapter;

public class Test1
{
    @XmlRootElement
    public static class Thingy
    {
        @XmlElements(@XmlElement(name = "row"))
        @XmlJavaTypeAdapter(type=Map.class, value=JAXBMapAdapter.class)
        public List<Map<String,Object>> rows;
    }

    public static void main(String[] args) throws Exception
    {
        Test1.Thingy thingy = new Test1.Thingy();

        Map<String,Object> thing1 = new HashMap<String,Object>();
        thing1.put("foo", "bar");
        thing1.put("date", new Date());

        Map<String,Object> thing2 = new HashMap<String,Object>();
        thing2.put("foo", "baz");
        thing2.put("date", new Date());

        List<Map<String,Object>> things = new ArrayList<Map<String,Object>>();
        things.add(thing1);
        things.add(thing2);

        thingy.rows = things;

        java.io.StringWriter sw = new java.io.StringWriter();
        JAXB.marshal(thingy, sw);
        System.out.print(sw.toString());
    }

}

これはこれを生成します:

<thingy>
    <row>
        <entry key="foo">
            <value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">bar</value>
        </entry>
        <entry key="date">
            <value xsi:type="xs:dateTime" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">2012-08-19T13:20:57.484-04:00</value>
        </entry>
    </row>
    <row>
        <entry key="foo">
            <value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">baz</value>
        </entry>
        <entry key="date">
            <value xsi:type="xs:dateTime" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">2012-08-19T13:20:57.484-04:00</value>
        </entry>
    </row>
</thingy>

私が本当に望んでいるvalueのは、エントリ内のネストされたタグを捨てることです。私の素朴な仮定は、@XmlElement注釈を にvalue置き換えることができるというものでした@XmlValue。ただし、これにより、JAXB は次のように床全体に吐き出します。

Exception in thread "main" java.lang.NullPointerException
    at com.sun.xml.internal.bind.v2.runtime.reflect.TransducedAccessor.get(TransducedAccessor.java:154)
    at com.sun.xml.internal.bind.v2.runtime.property.ValueProperty.<init>(ValueProperty.java:66)
    at com.sun.xml.internal.bind.v2.runtime.property.PropertyFactory.create(PropertyFactory.java:95)
    at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.<init>(ClassBeanInfoImpl.java:145)
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:479)
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:498)
    at com.sun.xml.internal.bind.v2.runtime.property.ArrayElementProperty.<init>(ArrayElementProperty.java:97)
    at com.sun.xml.internal.bind.v2.runtime.property.ArrayElementNodeProperty.<init>(ArrayElementNodeProperty.java:47)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at com.sun.xml.internal.bind.v2.runtime.property.PropertyFactory.create(PropertyFactory.java:113)
    at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.<init>(ClassBeanInfoImpl.java:145)
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:479)
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:498)
    at com.sun.xml.internal.bind.v2.runtime.property.ArrayElementProperty.<init>(ArrayElementProperty.java:97)
    at com.sun.xml.internal.bind.v2.runtime.property.ArrayElementNodeProperty.<init>(ArrayElementNodeProperty.java:47)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at com.sun.xml.internal.bind.v2.runtime.property.PropertyFactory.create(PropertyFactory.java:113)
    at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.<init>(ClassBeanInfoImpl.java:145)
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:479)
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:305)
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1100)
    at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:143)
    at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:110)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:202)
    at javax.xml.bind.ContextFinder.find(ContextFinder.java:376)
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:574)
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:522)
    at javax.xml.bind.JAXB$Cache.<init>(JAXB.java:87)
    at javax.xml.bind.JAXB.getContext(JAXB.java:114)
    at javax.xml.bind.JAXB._marshal(JAXB.java:538)
    at javax.xml.bind.JAXB.marshal(JAXB.java:431)
    at net.parkerson.test1.Test1.main(Test1.java:49)

ベースのコードを使用してこれを行う方法があると確信していますXmlAdapterが、これを考え出すにはあまりにも長い間これを見つめていたと思います!

4

1 に答える 1

1

変。マップ タイプを から<String, Object>に変更する<String, String>と、期待どおりに機能します。

更新: @XmlValue (または @XmlAttribute) で値をレンダリングするように JAXB を強制すると、型情報を配置する場所がないようです: xsi:type="xs:dateTime" ...@XmlElement である必要があります

私の提案は、基になる型に応じてtoMap<String, String>をエンコード/デコードするアダプターでa を使用することです。StringObject

public class MySmartAdapter extends XmlAdapter<String, Object> {
    @Override
    public Object unmarshal(String s) throws Exception {
        //check if s is date and return date
        //check for other types
        return s;
    }

    @Override
    public String marshal(Object o) throws Exception {
        return o != null ? o.toString() : null;
    }
}


public static class JAXBMapEntry
{

    @XmlAttribute
    public String key;

    @XmlValue
    @XmlJavaTypeAdapter(MySmartAdapter.class)
    public Object value;

    public JAXBMapEntry()
    {
    }

    public JAXBMapEntry(Map.Entry<String, Object> entry)
    {
        key = entry.getKey();
        value = entry.getValue();
    }
}
于 2012-08-19T18:58:40.783 に答える