View Javadoc
1   /*
2    * Copyright 2002-2014 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.http.converter.xml;
18  
19  import java.lang.reflect.Type;
20  import java.util.Collection;
21  import java.util.List;
22  import java.util.Set;
23  import javax.xml.bind.annotation.XmlAttribute;
24  import javax.xml.bind.annotation.XmlElement;
25  import javax.xml.bind.annotation.XmlRootElement;
26  import javax.xml.bind.annotation.XmlType;
27  import javax.xml.stream.XMLInputFactory;
28  
29  import org.junit.Before;
30  import org.junit.Test;
31  
32  import org.springframework.core.ParameterizedTypeReference;
33  import org.springframework.core.io.ClassPathResource;
34  import org.springframework.core.io.Resource;
35  import org.springframework.http.MockHttpInputMessage;
36  
37  import static org.junit.Assert.*;
38  
39  /**
40   * Test fixture for {@link Jaxb2CollectionHttpMessageConverter}.
41   *
42   * @author Arjen Poutsma
43   */
44  public class Jaxb2CollectionHttpMessageConverterTests {
45  
46  	private Jaxb2CollectionHttpMessageConverter<?> converter;
47  
48  	private Type rootElementListType;
49  
50  	private Type rootElementSetType;
51  
52  	private Type typeListType;
53  
54  	private Type typeSetType;
55  
56  
57  	@Before
58  	public void setUp() {
59  		converter = new Jaxb2CollectionHttpMessageConverter<Collection<Object>>();
60  		rootElementListType = new ParameterizedTypeReference<List<RootElement>>() {}.getType();
61  		rootElementSetType = new ParameterizedTypeReference<Set<RootElement>>() {}.getType();
62  		typeListType = new ParameterizedTypeReference<List<TestType>>() {}.getType();
63  		typeSetType = new ParameterizedTypeReference<Set<TestType>>() {}.getType();
64  	}
65  
66  	@Test
67  	public void canRead() throws Exception {
68  		assertTrue(converter.canRead(rootElementListType, null, null));
69  		assertTrue(converter.canRead(rootElementSetType, null, null));
70  		assertTrue(converter.canRead(typeSetType, null, null));
71  	}
72  
73  	@Test
74  	@SuppressWarnings("unchecked")
75  	public void readXmlRootElementList() throws Exception {
76  		String content = "<list><rootElement><type s=\"1\"/></rootElement><rootElement><type s=\"2\"/></rootElement></list>";
77  		MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes("UTF-8"));
78  
79  		List<RootElement> result = (List<RootElement>) converter.read(rootElementListType, null, inputMessage);
80  
81  		assertEquals("Invalid result", 2, result.size());
82  		assertEquals("Invalid result", "1", result.get(0).type.s);
83  		assertEquals("Invalid result", "2", result.get(1).type.s);
84  	}
85  
86  	@Test
87  	@SuppressWarnings("unchecked")
88  	public void readXmlRootElementSet() throws Exception {
89  		String content = "<set><rootElement><type s=\"1\"/></rootElement><rootElement><type s=\"2\"/></rootElement></set>";
90  		MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes("UTF-8"));
91  
92  		Set<RootElement> result = (Set<RootElement>) converter.read(rootElementSetType, null, inputMessage);
93  
94  		assertEquals("Invalid result", 2, result.size());
95  		assertTrue("Invalid result", result.contains(new RootElement("1")));
96  		assertTrue("Invalid result", result.contains(new RootElement("2")));
97  	}
98  
99  	@Test
100 	@SuppressWarnings("unchecked")
101 	public void readXmlTypeList() throws Exception {
102 		String content = "<list><foo s=\"1\"/><bar s=\"2\"/></list>";
103 		MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes("UTF-8"));
104 
105 		List<TestType> result = (List<TestType>) converter.read(typeListType, null, inputMessage);
106 
107 		assertEquals("Invalid result", 2, result.size());
108 		assertEquals("Invalid result", "1", result.get(0).s);
109 		assertEquals("Invalid result", "2", result.get(1).s);
110 	}
111 
112 	@Test
113 	@SuppressWarnings("unchecked")
114 	public void readXmlTypeSet() throws Exception {
115 		String content = "<set><foo s=\"1\"/><bar s=\"2\"/></set>";
116 		MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes("UTF-8"));
117 
118 		Set<TestType> result = (Set<TestType>) converter.read(typeSetType, null, inputMessage);
119 
120 		assertEquals("Invalid result", 2, result.size());
121 		assertTrue("Invalid result", result.contains(new TestType("1")));
122 		assertTrue("Invalid result", result.contains(new TestType("2")));
123 	}
124 
125 	@Test
126 	@SuppressWarnings("unchecked")
127 	public void readXmlRootElementExternalEntityDisabled() throws Exception {
128 
129 		Resource external = new ClassPathResource("external.txt", getClass());
130 		String content =  "<!DOCTYPE root [" +
131 				"  <!ELEMENT external ANY >\n" +
132 				"  <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]>" +
133 				"  <list><rootElement><type s=\"1\"/><external>&ext;</external></rootElement></list>";
134 		MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes("UTF-8"));
135 
136 		Collection<RootElement> result = converter.read(rootElementListType, null, inputMessage);
137 		assertEquals(1, result.size());
138 		assertEquals("", result.iterator().next().external);
139 	}
140 
141 	@Test
142 	@SuppressWarnings("unchecked")
143 	public void readXmlRootElementExternalEntityEnabled() throws Exception {
144 
145 		Resource external = new ClassPathResource("external.txt", getClass());
146 		String content =  "<!DOCTYPE root [" +
147 				"  <!ELEMENT external ANY >\n" +
148 				"  <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]>" +
149 				"  <list><rootElement><type s=\"1\"/><external>&ext;</external></rootElement></list>";
150 		MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes("UTF-8"));
151 
152 		Jaxb2CollectionHttpMessageConverter<?> c = new Jaxb2CollectionHttpMessageConverter<Collection<Object>>() {
153 			@Override
154 			protected XMLInputFactory createXmlInputFactory() {
155 				XMLInputFactory inputFactory = XMLInputFactory.newInstance();
156 				inputFactory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, true);
157 				return inputFactory;
158 			}
159 		};
160 
161 		Collection<RootElement> result = c.read(rootElementListType, null, inputMessage);
162 		assertEquals(1, result.size());
163 		assertEquals("Foo Bar", result.iterator().next().external);
164 	}
165 
166 
167 	@XmlRootElement
168 	public static class RootElement {
169 
170 		public RootElement() {
171 		}
172 
173 		public RootElement(String s) {
174 			this.type = new TestType(s);
175 		}
176 
177 		@XmlElement
178 		public TestType type = new TestType();
179 
180 		@XmlElement(required=false)
181 		public String external;
182 
183 		@Override
184 		public boolean equals(Object o) {
185 			if (this == o) {
186 				return true;
187 			}
188 			if (o instanceof RootElement) {
189 				RootElement other = (RootElement) o;
190 				return this.type.equals(other.type);
191 			}
192 			return false;
193 		}
194 
195 		@Override
196 		public int hashCode() {
197 			return type.hashCode();
198 		}
199 	}
200 
201 	@XmlType
202 	public static class TestType {
203 
204 		public TestType() {
205 		}
206 
207 		public TestType(String s) {
208 			this.s = s;
209 		}
210 
211 		@XmlAttribute
212 		public String s = "Hello World";
213 
214 		@Override
215 		public boolean equals(Object o) {
216 			if (this == o) {
217 				return true;
218 			}
219 			if (o instanceof TestType) {
220 				TestType other = (TestType) o;
221 				return this.s.equals(other.s);
222 			}
223 			return false;
224 		}
225 
226 		@Override
227 		public int hashCode() {
228 			return s.hashCode();
229 		}
230 	}
231 
232 }