Elim的博客

用来记录一些原创性的总结


Elim

JAXB系列之Map转换为XML之方法二

在上一篇博文中,我们使用了一个自定义的XmlMap类用以封装类似于Map的结构以存储数据,然后把它转换为XML。但是它的结构比较简单,如果我们需要使用真实的Map的话,我们需要把我们的XmlMap实现java.util.Map接口,然后实现其中的各个方法并把它们转换为ArrayList中的一个元素。这显然是比较麻烦的。为此笔者提供了一种把真实的Map转换为XML的方法,而不是直接使用自定义的XmlMap。大体思路是定义一个XmlAdapter,把一个真实类型的Map转换为XmlMap,然后在转换为XML时还是根据XmlMap来进行转换,这对它的使用者来讲会更加的友好。使用者不用关心是怎么转换的,只需要按照正常的逻辑使用Map结构即可。

定义了一个MapAdapter,其实现如下:

	public static class MapAdapter extends XmlAdapter<XmlMap, Map<String, String>> {

		@Override
		public Map<String, String> unmarshal(XmlMap v) throws Exception {
			return null;
		}

		@Override
		public XmlMap marshal(Map<String, String> v) throws Exception {
			if (v != null) {
				XmlMap xmlMap = new XmlMap();
				for (Map.Entry<String, String> entry : v.entrySet()) {
					xmlMap.put(entry.getKey(), entry.getValue());
				}
				return xmlMap;
			}
			return null;
		}

		
	}

然后XmlMap的结构也要改一改,不再继承自ArrayList,而是直接持有一个List类型的属性,因为使用了XMLAdapter后,XmlMap会被直接当做一个对象进行转换,而不是像方法一那样被当做一个集合来进行转换。因此为了确保其能够正确的输出key/value形式的元素,我们将XmlMap改造为如下这样。

	@XmlAccessorType(XmlAccessType.FIELD)
	public static class XmlMap {

		@XmlElementRef(name="xmlMap")
		private List<JAXBElement<String>> elements = new ArrayList<>();
		private static ObjectFactory objectFactory = new ObjectFactory();
		
		public void put(String key, String value) {
			JAXBElement<String> ele = objectFactory.createXmlMap(key, value);
			this.elements.add(ele);
		}
		
	}

ObjectFactory的内容还是不变。然后Request中的condition定义为java.util.Map类型。

	@XmlRootElement
	@XmlAccessorType(XmlAccessType.FIELD)
	public static class Request {
		
		@XmlJavaTypeAdapter(MapAdapter.class)
		private Map<String, String> condition;

		@Override
		public String toString() {
			return "Request [condition=" + condition + "]";
		}
		
	}

测试代码如下:

	@Test
	public void test() throws Exception {
		Request request = new Request();
		Map<String, String> condition = new LinkedHashMap<>();
		for (int i=0; i<5; i++) {
			condition.put("key_" + i, "value_" + i);
		}
		request.condition = condition;
		
		JAXBContext jaxbContext = JAXBContext.newInstance(Request.class, ObjectFactory.class);
		Marshaller marshaller = jaxbContext.createMarshaller();
		marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		marshaller.marshal(request, System.out);
	}

输出结果如下:

<request>
    <condition>
        <key_0>value_0</key_0>
        <key_1>value_1</key_1>
        <key_2>value_2</key_2>
        <key_3>value_3</key_3>
        <key_4>value_4</key_4>
    </condition>
</request>

也正常的按照我们想要的Map结构进行了输出。以下是完整代码。

	@Test
	public void test() throws Exception {
		Request request = new Request();
		Map<String, String> condition = new LinkedHashMap<>();
		for (int i=0; i<5; i++) {
			condition.put("key_" + i, "value_" + i);
		}
		request.condition = condition;
		
		JAXBContext jaxbContext = JAXBContext.newInstance(Request.class, ObjectFactory.class);
		Marshaller marshaller = jaxbContext.createMarshaller();
		marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		marshaller.marshal(request, System.out);
	}
	
	@XmlRootElement
	@XmlAccessorType(XmlAccessType.FIELD)
	public static class Request {
		
		@XmlJavaTypeAdapter(MapAdapter.class)
		private Map<String, String> condition;

		@Override
		public String toString() {
			return "Request [condition=" + condition + "]";
		}
		
	}
	
	public static class MapAdapter extends XmlAdapter<XmlMap, Map<String, String>> {

		@Override
		public Map<String, String> unmarshal(XmlMap v) throws Exception {
			return null;
		}

		@Override
		public XmlMap marshal(Map<String, String> v) throws Exception {
			if (v != null) {
				XmlMap xmlMap = new XmlMap();
				for (Map.Entry<String, String> entry : v.entrySet()) {
					xmlMap.put(entry.getKey(), entry.getValue());
				}
				return xmlMap;
			}
			return null;
		}

		
	}
	
	@XmlRegistry
	public static class ObjectFactory {
		
		@XmlElementDecl(name="xmlMap")
		public JAXBElement<String> createXmlMap(String key, String value) {
			QName name = new QName(key);
			JAXBElement<String> ele = new JAXBElement<>(name, String.class, value);
			return ele;
		}
		
	}
	
	@XmlAccessorType(XmlAccessType.FIELD)
	public static class XmlMap {

		@XmlElementRef(name="xmlMap")
		private List<JAXBElement<String>> elements = new ArrayList<>();
		private static ObjectFactory objectFactory = new ObjectFactory();
		
		public void put(String key, String value) {
			JAXBElement<String> ele = objectFactory.createXmlMap(key, value);
			this.elements.add(ele);
		}
		
	}

(注:本文由Elim写于2017年8月9日)