JAXB和java.util.Map

具有讽刺意味的是,可能很难在JAXB(JSR-222)中映射java.util.Map类? 在这篇文章中,我将介绍一些使其变得更容易的项目。

Java模型

以下是我们将用于此示例的Java模型。

顾客

Customer类具有Map类型的属性。 我之所以选择此Map,是因为键是一个域对象,而值是一个域对象。

package blog.map;

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class Customer {

    private Map<String, Address> addressMap = new HashMap<String, Address>();

    public Map<String, Address> getAddressMap() {
        return addressMap;
    }

    public void setAddressMap(Map<String, Address> addressMap) {
        this.addressMap = addressMap;
    }

}
地址

Address类只是典型的POJO。

package blog.map;

public class Address {

    private String street;

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

}

示范代码

在下面的演示代码中,我们将创建一个Customer实例并填充其Map属性。 然后,将其封送为XML。

package blog.map;

import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Customer.class);

        Address billingAddress = new Address();
        billingAddress.setStreet('1 A Street');

        Address shippingAddress = new Address();
        shippingAddress.setStreet('2 B Road');

        Customer customer = new Customer();
        customer.getAddressMap().put('billing', billingAddress);
        customer.getAddressMap().put('shipping', shippingAddress);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
    }

}

用例#1 –默认表示

以下是与我们的域模型相对应的XML示例。 我们看到Map中的每个项目都有包裹在entry元素中的keyvalue元素。

<?xml version='1.0' encoding='UTF-8'?>
<customer>
    <addressMap>
        <entry>
            <key>shipping</key>
            <value>
                <street>2 B Road</street>
            </value>
        </entry>
        <entry>
            <key>billing</key>
            <value>
                <street>1 A Street</street>
            </value>
        </entry>
    </addressMap>
</customer>

用例2 –重命名元素

JAXB参考实现使用@XmlElementWrapper批注来重命名与Map属性相对应的元素(我们已在EclipseLink 2.4.2和2.5.0中向MOXy添加了此支持)。 在MOXy的早期版本中,应使用@XmlElement批注。

顾客

我们将使用@XmlElementWrapper批注将与addressMap属性对应的元素重命名为address

package blog.map;

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class Customer {

    private Map<String, Address> addressMap = new HashMap<String, Address>();

    @XmlElementWrapper(name='addresses')
    public Map<String, Address> getAddressMap() {
        return addressMap;
    }

    public void setAddressMap(Map<String, Address> addressMap) {
        this.addressMap = addressMap;
    }

}
输出量

现在我们看到的是,addressMap元素已被重新命名为地址

<?xml version='1.0' encoding='UTF-8'?>
<customer>
    <addresses>
        <entry>
            <key>shipping</key>
            <value>
                <street>2 B Road</street>
            </value>
        </entry>
        <entry>
            <key>billing</key>
            <value>
                <street>1 A Street</street>
            </value>
        </entry>
    </addresses>
</customer>

用例#3 –添加命名空间资格

在此用例中,我们将研究将名称空间限定应用于属性类型为java.util.Map的类的影响。 有一个与Map属性的名称空间限定有关的MOXy错误,已在EclipseLink 2.4.2和2.5.0中修复(请参见: http : //bugs.eclipse.org/399297 )。

包装信息

我们将使用包级别@XmlSchema批注来指定属于该包中的类的所有字段/属性都应使用http://www.example.com命名空间进行限定(请参阅: JAXB&Namespaces )。

@XmlSchema(
    namespace='http://www.example.com',
    elementFormDefault=XmlNsForm.QUALIFIED)
package blog.map;

import javax.xml.bind.annotation.*;
输出量

我们看到与CustomerAddress类相对应的元素是名称空间限定的,但与Map类相对应的元素则不是。 这是因为Map类来自java.util包,因此我们在包级别@XmlSchema注释中指定的信息不适用。

<?xml version='1.0' encoding='UTF-8'?>
<ns2:customer xmlns:ns2='http://www.example.com'>
    <ns2:addresses>
        <entry>
            <key>shipping</key>
            <value>
                <ns2:street>2 B Road</ns2:street>
            </value>
        </entry>
        <entry>
            <key>billing</key>
            <value>
                <ns2:street>1 A Street</ns2:street>
            </value>
        </entry>
    </ns2:addresses>
</ns2:customer>

用例#4 –使用XmlAdapter修复命名空间资格

我们可以使用XmlAdapter来调整前一个用例的名称空间限定。

XmlAdapter(MapAdapter)

XmlAdapter机制允许您将一个类转换为另一个类,以影响映射(请参阅: XmlAdapter – JAXB的Secret Weapon )。 为了获得适当的名称空间限定,我们将使用XmlAdapterMap转换为域模型包中的对象。

package blog.map;

import java.util.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class MapAdapter extends XmlAdapter<MapAdapter.AdaptedMap, Map<String, Address>> {

    public static class AdaptedMap {

        public List<Entry> entry = new ArrayList<Entry>();

    }

    public static class Entry {

        public String key;

        public Address value;

    }

    @Override
    public Map<String, Address> unmarshal(AdaptedMap adaptedMap) throws Exception {
        Map<String, Address> map = new HashMap<String, Address>();
        for(Entry entry : adaptedMap.entry) {
            map.put(entry.key, entry.value);
        }
        return map;
    }

    @Override
    public AdaptedMap marshal(Map<String, Address> map) throws Exception {
        AdaptedMap adaptedMap = new AdaptedMap();
        for(Map.Entry<String, Address> mapEntry : map.entrySet()) {
            Entry entry = new Entry();
            entry.key = mapEntry.getKey();
            entry.value = mapEntry.getValue();
            adaptedMap.entry.add(entry);
        }
        return adaptedMap;
    }

}
顾客

@XmlJavaTypeAdapter批注用于在Map属性上指定XmlAdapter 。 请注意,在应用XmlAdaper的情况下,我们需要将@XmlElementWrapper批注更改为@XmlElement (证明应该使用@XmlElement来注释Map属性的元素)。

package blog.map;

import java.util.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
public class Customer {

    private Map<String, Address> addressMap = new HashMap<String, Address>();

    @XmlJavaTypeAdapter(MapAdapter.class)
    @XmlElement(name='addresses')
    public Map<String, Address> getAddressMap() {
        return addressMap;
    }

    public void setAddressMap(Map<String, Address> addressMap) {
        this.addressMap = addressMap;
    }

}
输出量

现在,XML输出中的所有元素都已使用http://www.example.com命名空间进行了限定。

<?xml version='1.0' encoding='UTF-8'?>
<customer xmlns='http://www.example.com'>
    <addresses>
        <entry>
            <key>shipping</key>
            <value>
                <street>2 B Road</street>
            </value>
        </entry>
        <entry>
            <key>billing</key>
            <value>
                <street>1 A Street</street>
            </value>
        </entry>
    </addresses>
</customer>

参考: Java XML和JSON绑定博客我们的JCG合作伙伴 Blaise Doughan的JAXB和java.util.Map

翻译自: https://www.javacodegeeks.com/2013/03/jaxb-and-java-util-map.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值