JAXB 深入显出 - JAXB 教程 Map 转化为XML

x33g5p2x  于2021-12-28 转载在 其他  
字(3.2k)|赞(0)|评价(0)|浏览(411)

摘要: 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 项目中使用案例。

相关文章