1. 程式人生 > >JAXB 深入顯出 - JAXB 教程 Map 轉化為XML

JAXB 深入顯出 - JAXB 教程 Map 轉化為XML

摘要: JAXB 作為JDK的一部分,能便捷地將Java物件與XML進行相互轉換,本教程從實際案例出發來講解JAXB 2 的那些事兒。完整版目錄

前情回顧

上節介紹的是關於List的轉換方式,這一節開始,將基於Map這種資料型別做轉換。

Java 物件中含有 Map

這裡的 Product.java 含有一個Map型別的屬性。

public class Product {

	private String id;
	private Map<String, String> item;
//  ignore setters/getters
}

首先來測試一下,和之前的章節一樣的結構,不多做解釋:

	@Test
	public void test1() throws JAXBException {
		Map<String, String> map = new HashMap<>();
		map.put("衣服", "大衣");
		map.put("褲子", "西褲");
		Product product = new Product();
		product.setId("1401");
		product.setItem(map);
		
		JAXB.marshal(product, System.out);
	}

看一下結果:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<product> <id>1401</id> <item> <entry> <key>衣服</key> <value>大衣</value> </entry> <entry> <key>褲子</key> <value>西褲</value> </entry
>
</item> </product>

結果比較奇怪,每一組Map資料被解析成了 <entry><key><value> 結構,通過之前的知識,改變<product>節點下的<id><item>的值是可以輕鬆做到的。而這裡的<key><value>並不是我們希望顯示的節點名稱,這就需要進行改造了。

Map節點的名稱變更

改造需要的程式碼量比較多,因為JAXB原生不指定Map的自定義操作。也可以說JAXB不支援Map這種資料型別。所以需要使用到介面卡來擴充套件Jaxb的功能。

首先定義一個類,其中只有兩個欄位,為了簡單,可以不寫setters/getters方法。通過這種方式模擬一個Map,只包含key/value,也就是first/second,這個名稱就是XML的節點顯示名稱。

public class XmlMap {

	public String first;
	public String second;
}

自定義一個Adapter,這裡將所有的程式碼都展示出來。

public class MapAdapter extends XmlAdapter<XmlMap[], Map<String, String>>{
	@Override
	public Map<String, String> unmarshal(XmlMap[] v) throws Exception {
		Map<String, String> map = new HashMap<>();
		for(int i=0;i<v.length;i++) {
			XmlMap pairs = v[i];
			map.put(pairs.first, pairs.second);
		}
		return map;
	}
	@Override
	public XmlMap[] marshal(Map<String, String> v) throws Exception {
		XmlMap[] xmlMap = new XmlMap[v.size()];
		int index = 0;
		for(Map.Entry<String, String> entry: v.entrySet()) {
			XmlMap xm = new XmlMap();
			xm.first = entry.getKey();
			xm.second = entry.getValue();
			xmlMap[index++] = xm;
		}
		return xmlMap;
	}
}

@XmlJavaTypeAdapterJAXB能夠內建支援List和Set集合,但是對於Map的支援需要自己處理。它繼承自抽象類XmlAdapter<ValueType,BoundType>
型別引數:

  • BoundType JAXB 不知道如何處理的一些型別。自定義的型別,告訴Jaxb ValueType 將此型別用作記憶體表示形式。
  • ValueType JAXB 無需其他操作便知道如何處理的型別。

這裡的Map對於JAXB是一個未知型別,但是XmlMap[]卻是已知的物件陣列型別。通過中間的轉化賦值,可以使XmlMap[]Map相互轉化,從而讓Jaxb知道資料如何處理。

在之前的Product中,在Map上加上註解@XmlJavaTypeAdapter(MapAdapter.class)

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Product2 {

	private String id;

	@XmlJavaTypeAdapter(MapAdapter.class)
	public Map<String, String> category;
//  setters, getters

測試一下:

@Test 
	public void test2() throws JAXBException {
		Map<String, String> map = new HashMap<>();
		map.put("衣服", "大衣");
		map.put("褲子", "西褲");
		Product2 product = new Product2();
		product.setId("1402");
		product.setCategory(map);
		
		JAXB.marshal(product, System.out);
	}

得到的結果:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<product2>
    <id>1402</id>
    <category>
        <item>
            <first>衣服</first>
            <second>大衣</second>
        </item>
        <item>
            <first>褲子</first>
            <second>西褲</second>
        </item>
    </category>
</product2>

上面的所有節點名稱除了item都是可以通過已經講述的方法改變的。

完整程式碼

可以在GitHub找到完整程式碼。
本節程式碼均在該包下:package com.example.demo.lesson14;

下節預覽

本節介紹了 JAXB 中Map 的相關轉化。下節開始,將開始講述Jaxb在 Spring 專案中使用案例。