Elim的博客

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


Elim

JAXB系列之文本标签不自动转译

在上文介绍了文本标签如果内容中包含了XML元素时会自动的被JAXB进行转译。示例代码如下:

	@Test
	public void testMarshal() {
		Response response = new Response();
		response.setCode(200);
		response.setMessage("success");
		response.setReturnValue("<a><b>123</b></a>");
		JAXB.marshal(response, System.out);
	}
	
	@XmlRootElement
	public static class Response {
		private int code;
		private String message;
		private String returnValue;
		
		public int getCode() {
			return code;
		}
		public void setCode(int code) {
			this.code = code;
		}
		public String getMessage() {
			return message;
		}
		public void setMessage(String message) {
			this.message = message;
		}
		public String getReturnValue() {
			return returnValue;
		}
		public void setReturnValue(String returnValue) {
			this.returnValue = returnValue;
		}
		
	}

输出如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<response>
    <code>200</code>
    <message>success</message>
    <returnValue>&lt;a&gt;&lt;b&gt;123&lt;/b&gt;&lt;/a&gt;</returnValue>
</response>

我们可以看到returnValue属性值<a><b>123</b></a>被成功的转译了。JAXB对标签转译是通过com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler实现类来进行的,默认的实现类是会对标签进行转译的。所以我们只需要实现自己的com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler,然后在实现中对文本不进行转译即可。为此定义了如下这样一个CharacterEscapeHandler

	@SuppressWarnings("restriction")
	public static class MyCharacterEscapeHandler implements com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler {

		public static final MyCharacterEscapeHandler INSTANCE = new MyCharacterEscapeHandler();
		
		private MyCharacterEscapeHandler() {
		}
		
		@Override
		public void escape(char[] chars, int start, int length, boolean isAttVal, Writer out) throws IOException {
			//直接输出文本即可,即原样输出,默认实现,这里是会进行转译的。
			out.write(chars, start, length);
		}
		
	}

然后需要用它来替换掉默认实现。在下面代码中通过marshaller.setProperty("com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler", MyCharacterEscapeHandler.INSTANCE);这句实现的。

	@Test
	public void testMarshal() throws Exception {
		Response response = new Response();
		response.setCode(200);
		response.setMessage("success");
		response.setReturnValue("<a><b>123</b></a>");
		
		
		JAXBContext jaxbContext = JAXBContext.newInstance(Response.class);
		Marshaller marshaller = jaxbContext.createMarshaller();
		marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		//替换默认的CharacterEscapeHandler实现为我们自己的实现
		marshaller.setProperty("com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler", MyCharacterEscapeHandler.INSTANCE);
		marshaller.marshal(response, System.out);
	}

之后再次对之前的对象进行marshal时将输出如下内容。我们可以看到这个时候我们的returnValue的值没有再被转译了。但是它在被应用时如果需要转换为Response对象是走不通的,这在之前的《JAXB系列之通过XmlJavaTypeAdapter自动加上CDATA》一问中有说明。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<response>
    <code>200</code>
    <message>success</message>
    <returnValue><a><b>123</b></a></returnValue>
</response>

(本文由Elim写于2017年7月29日)