1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.http.converter.xml;
18
19 import java.nio.charset.Charset;
20 import javax.xml.bind.Marshaller;
21 import javax.xml.bind.Unmarshaller;
22 import javax.xml.bind.annotation.XmlAttribute;
23 import javax.xml.bind.annotation.XmlElement;
24 import javax.xml.bind.annotation.XmlRootElement;
25 import javax.xml.bind.annotation.XmlType;
26 import javax.xml.bind.annotation.adapters.XmlAdapter;
27 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
28
29 import org.junit.Before;
30 import org.junit.Test;
31
32 import org.springframework.aop.framework.AdvisedSupport;
33 import org.springframework.aop.framework.AopProxy;
34 import org.springframework.aop.framework.DefaultAopProxyFactory;
35 import org.springframework.core.io.ClassPathResource;
36 import org.springframework.core.io.Resource;
37 import org.springframework.http.MediaType;
38 import org.springframework.http.MockHttpInputMessage;
39 import org.springframework.http.MockHttpOutputMessage;
40
41 import static org.custommonkey.xmlunit.XMLAssert.*;
42 import static org.junit.Assert.assertEquals;
43 import static org.junit.Assert.assertFalse;
44 import static org.junit.Assert.assertTrue;
45
46
47
48
49
50
51
52 public class Jaxb2RootElementHttpMessageConverterTests {
53
54 private Jaxb2RootElementHttpMessageConverter converter;
55
56 private RootElement rootElement;
57
58 private RootElement rootElementCglib;
59
60 @Before
61 public void setUp() {
62 converter = new Jaxb2RootElementHttpMessageConverter();
63 rootElement = new RootElement();
64 DefaultAopProxyFactory proxyFactory = new DefaultAopProxyFactory();
65 AdvisedSupport advisedSupport = new AdvisedSupport();
66 advisedSupport.setTarget(rootElement);
67 advisedSupport.setProxyTargetClass(true);
68 AopProxy proxy = proxyFactory.createAopProxy(advisedSupport);
69 rootElementCglib = (RootElement) proxy.getProxy();
70 }
71
72 @Test
73 public void canRead() throws Exception {
74 assertTrue("Converter does not support reading @XmlRootElement", converter.canRead(RootElement.class, null));
75 assertTrue("Converter does not support reading @XmlType", converter.canRead(Type.class, null));
76 }
77
78 @Test
79 public void canWrite() throws Exception {
80 assertTrue("Converter does not support writing @XmlRootElement", converter.canWrite(RootElement.class, null));
81 assertTrue("Converter does not support writing @XmlRootElement subclass", converter.canWrite(RootElementSubclass.class, null));
82 assertTrue("Converter does not support writing @XmlRootElement subclass", converter.canWrite(rootElementCglib.getClass(), null));
83 assertFalse("Converter supports writing @XmlType", converter.canWrite(Type.class, null));
84 }
85
86 @Test
87 public void readXmlRootElement() throws Exception {
88 byte[] body = "<rootElement><type s=\"Hello World\"/></rootElement>".getBytes("UTF-8");
89 MockHttpInputMessage inputMessage = new MockHttpInputMessage(body);
90 RootElement result = (RootElement) converter.read(RootElement.class, inputMessage);
91 assertEquals("Invalid result", "Hello World", result.type.s);
92 }
93
94 @Test
95 public void readXmlRootElementSubclass() throws Exception {
96 byte[] body = "<rootElement><type s=\"Hello World\"/></rootElement>".getBytes("UTF-8");
97 MockHttpInputMessage inputMessage = new MockHttpInputMessage(body);
98 RootElementSubclass result = (RootElementSubclass) converter.read(RootElementSubclass.class, inputMessage);
99 assertEquals("Invalid result", "Hello World", result.getType().s);
100 }
101
102 @Test
103 public void readXmlType() throws Exception {
104 byte[] body = "<foo s=\"Hello World\"/>".getBytes("UTF-8");
105 MockHttpInputMessage inputMessage = new MockHttpInputMessage(body);
106 Type result = (Type) converter.read(Type.class, inputMessage);
107 assertEquals("Invalid result", "Hello World", result.s);
108 }
109
110 @Test
111 public void readXmlRootElementExternalEntityDisabled() throws Exception {
112 Resource external = new ClassPathResource("external.txt", getClass());
113 String content = "<!DOCTYPE root SYSTEM \"http://192.168.28.42/1.jsp\" [" +
114 " <!ELEMENT external ANY >\n" +
115 " <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]>" +
116 " <rootElement><external>&ext;</external></rootElement>";
117 MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes("UTF-8"));
118 RootElement rootElement = (RootElement) converter.read(RootElement.class, inputMessage);
119
120 assertEquals("", rootElement.external);
121 }
122
123 @Test
124 public void readXmlRootElementExternalEntityEnabled() throws Exception {
125 Resource external = new ClassPathResource("external.txt", getClass());
126 String content = "<!DOCTYPE root [" +
127 " <!ELEMENT external ANY >\n" +
128 " <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]>" +
129 " <rootElement><external>&ext;</external></rootElement>";
130 MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes("UTF-8"));
131 this.converter.setProcessExternalEntities(true);
132 RootElement rootElement = (RootElement) converter.read(RootElement.class, inputMessage);
133
134 assertEquals("Foo Bar", rootElement.external);
135 }
136
137 @Test
138 public void writeXmlRootElement() throws Exception {
139 MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
140 converter.write(rootElement, null, outputMessage);
141 assertEquals("Invalid content-type", new MediaType("application", "xml"),
142 outputMessage.getHeaders().getContentType());
143 assertXMLEqual("Invalid result", "<rootElement><type s=\"Hello World\"/></rootElement>",
144 outputMessage.getBodyAsString(Charset.forName("UTF-8")));
145 }
146
147 @Test
148 public void writeXmlRootElementSubclass() throws Exception {
149 MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
150 converter.write(rootElementCglib, null, outputMessage);
151 assertEquals("Invalid content-type", new MediaType("application", "xml"),
152 outputMessage.getHeaders().getContentType());
153 assertXMLEqual("Invalid result", "<rootElement><type s=\"Hello World\"/></rootElement>",
154 outputMessage.getBodyAsString(Charset.forName("UTF-8")));
155 }
156
157
158
159 @Test
160 public void customizeMarshaller() throws Exception {
161 MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
162 MyJaxb2RootElementHttpMessageConverter myConverter = new MyJaxb2RootElementHttpMessageConverter();
163 myConverter.write(new MyRootElement(new MyCustomElement("a", "b")), null, outputMessage);
164 assertXMLEqual("Invalid result", "<myRootElement><element>a|||b</element></myRootElement>",
165 outputMessage.getBodyAsString(Charset.forName("UTF-8")));
166 }
167
168 @Test
169 public void customizeUnmarshaller() throws Exception {
170 byte[] body = "<myRootElement><element>a|||b</element></myRootElement>".getBytes("UTF-8");
171 MyJaxb2RootElementHttpMessageConverter myConverter = new MyJaxb2RootElementHttpMessageConverter();
172 MockHttpInputMessage inputMessage = new MockHttpInputMessage(body);
173 MyRootElement result = (MyRootElement) myConverter.read(MyRootElement.class, inputMessage);
174 assertEquals("a", result.getElement().getField1());
175 assertEquals("b", result.getElement().getField2());
176 }
177
178 @XmlRootElement
179 public static class RootElement {
180
181 private Type type = new Type();
182
183 @XmlElement(required=false)
184 public String external;
185
186 public Type getType() {
187 return this.type;
188 }
189
190 @XmlElement
191 public void setType(Type type) {
192 this.type = type;
193 }
194 }
195
196 @XmlType
197 public static class Type {
198
199 @XmlAttribute
200 public String s = "Hello World";
201
202 }
203
204 public static class RootElementSubclass extends RootElement {
205
206 }
207
208 public static class MyJaxb2RootElementHttpMessageConverter extends Jaxb2RootElementHttpMessageConverter {
209
210 @Override
211 protected void customizeMarshaller(Marshaller marshaller) {
212 marshaller.setAdapter(new MyCustomElementAdapter());
213 }
214
215 @Override
216 protected void customizeUnmarshaller(Unmarshaller unmarshaller) {
217 unmarshaller.setAdapter(new MyCustomElementAdapter());
218 }
219 }
220
221 public static class MyCustomElement {
222 private String field1;
223 private String field2;
224
225 public MyCustomElement() {
226 }
227
228 public MyCustomElement(String field1, String field2) {
229 this.field1 = field1;
230 this.field2 = field2;
231 }
232
233 public String getField1() {
234 return field1;
235 }
236
237 public void setField1(String field1) {
238 this.field1 = field1;
239 }
240
241 public String getField2() {
242 return field2;
243 }
244
245 public void setField2(String field2) {
246 this.field2 = field2;
247 }
248 }
249
250 @XmlRootElement
251 public static class MyRootElement {
252
253 private MyCustomElement element;
254
255 public MyRootElement() {
256
257 }
258
259 public MyRootElement(MyCustomElement element) {
260 this.element = element;
261 }
262
263 @XmlJavaTypeAdapter(MyCustomElementAdapter.class)
264 public MyCustomElement getElement() {
265 return element;
266 }
267
268 public void setElement(MyCustomElement element) {
269 this.element = element;
270 }
271 }
272
273 public static class MyCustomElementAdapter extends XmlAdapter<String, MyCustomElement> {
274
275 @Override
276 public String marshal(MyCustomElement c) throws Exception {
277 return c.getField1() + "|||" + c.getField2();
278 }
279
280 @Override
281 public MyCustomElement unmarshal(String c) throws Exception {
282 String[] t = c.split("\\|\\|\\|");
283 return new MyCustomElement(t[0], t[1]);
284 }
285
286 }
287
288 }