具有讽刺意味的是,可能很难在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元素中的key和value元素。
<?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.*;
输出量
我们看到与Customer和Address类相对应的元素是名称空间限定的,但与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 )。 为了获得适当的名称空间限定,我们将使用XmlAdapter将Map转换为域模型包中的对象。
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;}@Overridepublic 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;}@Overridepublic 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