View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.xml;
18  
19  import static org.apache.juneau.TestUtils.*;
20  import static org.apache.juneau.xml.annotation.XmlFormat.*;
21  import static org.junit.jupiter.api.Assertions.*;
22  
23  import java.util.*;
24  
25  import org.apache.juneau.*;
26  import org.apache.juneau.annotation.*;
27  import org.apache.juneau.collections.*;
28  import org.apache.juneau.xml.annotation.*;
29  import org.junit.jupiter.api.*;
30  
31  class Common_Test extends TestBase {
32  
33  	//====================================================================================================
34  	// Trim nulls from beans
35  	//====================================================================================================
36  	@Test void a01_trimNullsFromBeans() throws Exception {
37  		var s = XmlSerializer.create().sq();
38  		var p = XmlParser.DEFAULT;
39  		var t1 = A.create();
40  
41  		var r = s.build().serialize(t1);
42  		assertEquals("<object><s2>s2</s2></object>", r);
43  		var t2 = p.parse(r, A.class);
44  		assertEquals(json(t2), json(t1));
45  
46  		s.keepNullProperties();
47  		r = s.build().serialize(t1);
48  		assertEquals("<object><s1 _type='null'/><s2>s2</s2></object>", r);
49  		t2 = p.parse(r, A.class);
50  		assertEquals(json(t2), json(t1));
51  	}
52  
53  	public static class A {
54  		public String s1, s2;
55  
56  		public static A create() {
57  			var t = new A();
58  			t.s2 = "s2";
59  			return t;
60  		}
61  	}
62  
63  	//====================================================================================================
64  	// Trim empty maps
65  	//====================================================================================================
66  	@Test void a02_trimEmptyMaps() throws Exception {
67  		var s = XmlSerializer.create().sq();
68  		var p = XmlParser.DEFAULT;
69  		var t1 = B.create();
70  		var r = s.build().serialize(t1);
71  
72  		assertEquals("<object><f1/><f2><f2a _type='null'/><f2b><s2>s2</s2></f2b></f2></object>", r);
73  		var t2 = p.parse(r, B.class);
74  		assertEquals(json(t2), json(t1));
75  
76  		s.trimEmptyMaps();
77  		r = s.build().serialize(t1);
78  		assertEquals("<object><f2><f2a _type='null'/><f2b><s2>s2</s2></f2b></f2></object>", r);
79  		t2 = p.parse(r, B.class);
80  		assertNull(t2.f1);
81  	}
82  
83  	public static class B {
84  		public TreeMap<String,A> f1, f2;
85  
86  		public static B create() {
87  			var t = new B();
88  			t.f1 = new TreeMap<>();
89  			t.f2 = new TreeMap<>(){{put("f2a",null);put("f2b",A.create());}};
90  			return t;
91  		}
92  	}
93  
94  	//====================================================================================================
95  	// Trim empty lists
96  	//====================================================================================================
97  	@Test void a03_trimEmptyLists() throws Exception {
98  		var s = XmlSerializer.create().sq();
99  		var p = XmlParser.DEFAULT;
100 		var t1 = C.create();
101 		var r = s.build().serialize(t1);
102 
103 		assertEquals("<object><f1></f1><f2><null/><object><s2>s2</s2></object></f2></object>", r);
104 		var t2 = p.parse(r, C.class);
105 		assertEquals(json(t2), json(t1));
106 
107 		s.trimEmptyCollections();
108 		r = s.build().serialize(t1);
109 		assertEquals("<object><f2><null/><object><s2>s2</s2></object></f2></object>", r);
110 		t2 = p.parse(r, C.class);
111 		assertNull(t2.f1);
112 	}
113 
114 	public static class C {
115 		public List<A> f1, f2;
116 
117 		public static C create() {
118 			var t = new C();
119 			t.f1 = list();
120 			t.f2 = list(null,A.create());
121 			return t;
122 		}
123 	}
124 
125 	//====================================================================================================
126 	// Trim empty arrays
127 	//====================================================================================================
128 	@Test void a04_trimEmptyArrays() throws Exception {
129 		var s = XmlSerializer.create().sq();
130 		var p = XmlParser.DEFAULT;
131 		var t1 = D.create();
132 		var r = s.build().serialize(t1);
133 
134 		assertEquals("<object><f1></f1><f2><null/><object><s2>s2</s2></object></f2></object>", r);
135 		var t2 = p.parse(r, D.class);
136 		assertEquals(json(t2), json(t1));
137 
138 		s.trimEmptyCollections();
139 		r = s.build().serialize(t1);
140 		assertEquals("<object><f2><null/><object><s2>s2</s2></object></f2></object>", r);
141 		t2 = p.parse(r, D.class);
142 		assertNull(t2.f1);
143 	}
144 
145 	public static class D {
146 		public A[] f1, f2;
147 
148 		public static D create() {
149 			var t = new D();
150 			t.f1 = new A[]{};
151 			t.f2 = new A[]{null, A.create()};
152 			return t;
153 		}
154 	}
155 
156 	//====================================================================================================
157 	// @Beanp.bpi annotation.
158 	//====================================================================================================
159 	@Test void a05_beanPropertyProperties() throws Exception {
160 		var s = XmlSerializer.DEFAULT_SQ;
161 		var t = new E1();
162 		var r = s.serialize(t);
163 		assertEquals(
164 			"<object>"
165 				+"<x1 f2='2'><f1>1</f1></x1>"
166 				+"<x2><f1>1</f1></x2>"
167 				+"<x3><object f2='2'><f1>1</f1></object></x3>"
168 				+"<x4><object f2='2'><f1>1</f1></object></x4>"
169 				+"<x5><object><f1 _type='number'>1</f1></object></x5>"
170 				+"<x6><object><f1 _type='number'>1</f1></object></x6>"
171 			+"</object>",
172 			r);
173 		validateXml(t);
174 	}
175 
176 	public static class E1 {
177 		@Beanp(properties="f1,f2") public E2 x1 = new E2();
178 		@Beanp(properties="f1,f2") public Map<String,Integer> x2 = map("f1",1,"f3",3);
179 		@Beanp(properties="f1,f2") public E2[] x3 = {new E2()};
180 		@Beanp(properties="f1,f2") public List<E2> x4 = list(new E2());
181 		@Beanp(properties="f1") public JsonMap[] x5 = {JsonMap.of("f1",1,"f3",3)};
182 		@Beanp(properties="f1") public List<JsonMap> x6 = list(JsonMap.of("f1",1,"f3",3));
183 	}
184 
185 	public static class E2 {
186 		public int f1 = 1;
187 		@Xml(format=ATTR) public int f2 = 2;
188 		public int f3 = 3;
189 		@Xml(format=ATTR) public int f4 = 4;
190 	}
191 
192 	//====================================================================================================
193 	// @Beanp.bpi annotation on list of beans.
194 	//====================================================================================================
195 	@Test void a06_beanPropertyPropertiesOnListOfBeans() throws Exception {
196 		var s = XmlSerializer.DEFAULT_SQ;
197 		var l = new LinkedList<>();
198 		var t = new Test7b();
199 		t.x1.add(new Test7b());
200 		l.add(t);
201 		var xml = s.serialize(l);
202 		assertEquals("<array><object><x1><object><x2>2</x2></object></x1><x2>2</x2></object></array>", xml);
203 	}
204 
205 	public static class Test7b {
206 		@Beanp(properties="x2") public List<Test7b> x1 = new LinkedList<>();
207 		public int x2 = 2;
208 	}
209 
210 	//====================================================================================================
211 	// Recursion
212 	//====================================================================================================
213 	@Test void a07_recursion() throws Exception {
214 		var s = XmlSerializer.create().maxDepth(Integer.MAX_VALUE);
215 
216 		var r1 = new R1();
217 		var r2 = new R2();
218 		var r3 = new R3();
219 		r1.r2 = r2;
220 		r2.r3 = r3;
221 		r3.r1 = r1;
222 
223 		// No recursion detection
224 		assertThrowsWithMessage(Exception.class, "It's recommended you use the BeanTraverseContext.BEANTRAVERSE_detectRecursions setting to help locate the loop.", ()->s.build().serialize(r1));
225 
226 		// Recursion detection, no ignore
227 		s.detectRecursions();
228 		assertThrowsWithMessage(
229 			Exception.class,
230 			list("[0] <noname>:org.apache.juneau.xml.Common_Test$R1", "->[1] r2:org.apache.juneau.xml.Common_Test$R2", "->[2] r3:org.apache.juneau.xml.Common_Test$R3", "->[3] r1:org.apache.juneau.xml.Common_Test$R1"),
231 			()->s.build().serialize(r1)
232 		);
233 
234 		s.ignoreRecursions();
235 		assertEquals("<object><name>foo</name><r2><name>bar</name><r3><name>baz</name></r3></r2></object>", s.build().serialize(r1));
236 	}
237 
238 	public static class R1 {
239 		public String name = "foo";
240 		public R2 r2;
241 	}
242 	public static class R2 {
243 		public String name = "bar";
244 		public R3 r3;
245 	}
246 	public static class R3 {
247 		public String name = "baz";
248 		public R1 r1;
249 	}
250 }