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.json;
18  
19  import static org.apache.juneau.TestUtils.*;
20  import static org.junit.jupiter.api.Assertions.*;
21  
22  import java.net.*;
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.junit.jupiter.api.*;
29  
30  class Common_Test  extends TestBase{
31  
32  	//====================================================================================================
33  	// Trim nulls from beans
34  	//====================================================================================================
35  	@Test void a01_trimNullsFromBeans() throws Exception {
36  		var s = JsonSerializer.create().json5();
37  		var p = JsonParser.DEFAULT;
38  		var t1 = A.create();
39  
40  		var r = s.build().serialize(t1);
41  		assertEquals("{s2:'s2'}", r);
42  		var t2 = p.parse(r, A.class);
43  		assertEquals(json(t2), json(t1));
44  
45  		s.keepNullProperties();
46  		r = s.build().serialize(t1);
47  		assertEquals("{s1:null,s2:'s2'}", r);
48  		t2 = p.parse(r, A.class);
49  		assertEquals(json(t2), json(t1));
50  	}
51  
52  	public static class A {
53  		public String s1, s2;
54  
55  		public static A create() {
56  			var t = new A();
57  			t.s2 = "s2";
58  			return t;
59  		}
60  	}
61  
62  	//====================================================================================================
63  	// Trim empty maps
64  	//====================================================================================================
65  	@Test void a02_trimEmptyMaps() throws Exception {
66  		var s = JsonSerializer.create().json5();
67  		var p = JsonParser.DEFAULT;
68  		var t1 = B.create();
69  		var r = s.build().serialize(t1);
70  
71  		assertEquals("{f1:{},f2:{f2a:null,f2b:{s2:'s2'}}}", r);
72  		var t2 = p.parse(r, B.class);
73  		assertEquals(json(t2), json(t1));
74  
75  		s.trimEmptyMaps();
76  		r = s.build().serialize(t1);
77  		assertEquals("{f2:{f2a:null,f2b:{s2:'s2'}}}", r);
78  		t2 = p.parse(r, B.class);
79  		assertNull(t2.f1);
80  	}
81  
82  	public static class B {
83  		public TreeMap<String,A> f1, f2;
84  
85  		public static B create() {
86  			var t = new B();
87  			t.f1 = new TreeMap<>();
88  			t.f2 = new TreeMap<>(){{put("f2a",null);put("f2b",A.create());}};
89  			return t;
90  		}
91  	}
92  
93  	//====================================================================================================
94  	// Trim empty lists
95  	//====================================================================================================
96  	@Test void a03_trimEmptyLists() throws Exception {
97  		var s = JsonSerializer.create().json5();
98  		var p = JsonParser.DEFAULT;
99  		var t1 = C.create();
100 		var r = s.build().serialize(t1);
101 
102 		assertEquals("{f1:[],f2:[null,{s2:'s2'}]}", r);
103 		var t2 = p.parse(r, C.class);
104 		assertEquals(json(t2), json(t1));
105 
106 		s.trimEmptyCollections();
107 		r = s.build().serialize(t1);
108 		assertEquals("{f2:[null,{s2:'s2'}]}", r);
109 		t2 = p.parse(r, C.class);
110 		assertNull(t2.f1);
111 	}
112 
113 	public static class C {
114 		public List<A> f1, f2;
115 
116 		public static C create() {
117 			var t = new C();
118 			t.f1 = list();
119 			t.f2 = list(null,A.create());
120 			return t;
121 		}
122 	}
123 
124 	//====================================================================================================
125 	// Trim empty arrays
126 	//====================================================================================================
127 	@Test void a04_trimEmptyArrays() throws Exception {
128 		var s = JsonSerializer.create().json5();
129 		var p = JsonParser.DEFAULT;
130 		var t1 = D.create();
131 		var r = s.build().serialize(t1);
132 
133 		assertEquals("{f1:[],f2:[null,{s2:'s2'}]}", r);
134 		var t2 = p.parse(r, D.class);
135 		assertEquals(json(t2), json(t1));
136 
137 		s.trimEmptyCollections();
138 		r = s.build().serialize(t1);
139 		assertEquals("{f2:[null,{s2:'s2'}]}", r);
140 		t2 = p.parse(r, D.class);
141 		assertNull(t2.f1);
142 	}
143 
144 	public static class D {
145 		public A[] f1, f2;
146 
147 		public static D create() {
148 			var t = new D();
149 			t.f1 = new A[]{};
150 			t.f2 = new A[]{null, A.create()};
151 			return t;
152 		}
153 	}
154 
155 	//====================================================================================================
156 	// @Beanp.bpi annotation.
157 	//====================================================================================================
158 	@Test void a05_beanPropertyProperies() throws Exception {
159 		var s = Json5Serializer.DEFAULT;
160 		var t = new E1();
161 		var r = s.serialize(t);
162 
163 		assertEquals("{x1:{f1:1},x2:{f1:1},x3:[{f1:1}],x4:[{f1:1}],x5:[{f1:1}],x6:[{f1:1}]}", r);
164 		r = s.getSchemaSerializer().serialize(t);
165 		assertEquals(r.indexOf("f2"), -1);
166 	}
167 
168 	public static class E1 {
169 		@Beanp(properties="f1") public E2 x1 = new E2();
170 		@Beanp(properties="f1") public Map<String,Integer> x2 = map("f1",1,"f2",2);
171 		@Beanp(properties="f1") public E2[] x3 = {new E2()};
172 		@Beanp(properties="f1") public List<E2> x4 = list(new E2());
173 		@Beanp(properties="f1") public JsonMap[] x5 = {JsonMap.of("f1",1,"f2",2)};
174 		@Beanp(properties="f1") public List<JsonMap> x6 = list(JsonMap.of("f1",1,"f2",2));
175 	}
176 
177 	public static class E2 {
178 		public int f1 = 1;
179 		public int f2 = 2;
180 	}
181 
182 	//====================================================================================================
183 	// @Beanp.bpi annotation on list of beans.
184 	//====================================================================================================
185 	@Test void a06_beanPropertyProperiesOnListOfBeans() throws Exception {
186 		var s = Json5Serializer.DEFAULT;
187 		var l = new LinkedList<>();
188 		var t = new F();
189 		t.x1.add(new F());
190 		l.add(t);
191 		var json = s.serialize(l);
192 		assertEquals("[{x1:[{x2:2}],x2:2}]", json);
193 	}
194 
195 	public static class F {
196 		@Beanp(properties="x2") public List<F> x1 = new LinkedList<>();
197 		public int x2 = 2;
198 	}
199 
200 	//====================================================================================================
201 	// Test that URLs and URIs are serialized and parsed correctly.
202 	//====================================================================================================
203 	@Test void a07_uRIAttr() throws Exception {
204 		var s = Json5Serializer.DEFAULT;
205 		var p = JsonParser.DEFAULT;
206 
207 		var t = new G();
208 		t.uri = new URI("http://uri");
209 		t.f1 = new URI("http://f1");
210 		t.f2 = url("http://f2");
211 
212 		var json = s.serialize(t);
213 		t = p.parse(json, G.class);
214 		assertEquals("http://uri", t.uri.toString());
215 		assertEquals("http://f1", t.f1.toString());
216 		assertEquals("http://f2", t.f2.toString());
217 	}
218 
219 	public static class G {
220 		public URI uri;
221 		public URI f1;
222 		public URL f2;
223 	}
224 
225 
226 	//====================================================================================================
227 	// Recursion
228 	//====================================================================================================
229 	@Test void a08_recursion() throws Exception {
230 		var s = JsonSerializer.create().json5().maxDepth(Integer.MAX_VALUE);
231 
232 		var r1 = new R1();
233 		var r2 = new R2();
234 		var r3 = new R3();
235 		r1.r2 = r2;
236 		r2.r3 = r3;
237 		r3.r1 = r1;
238 
239 		// No recursion detection
240 		assertThrowsWithMessage(Exception.class, "It's recommended you use the BeanTraverseContext.BEANTRAVERSE_detectRecursions setting to help locate the loop.", ()->s.build().serialize(r1));
241 
242 		// Recursion detection, no ignore
243 		s.detectRecursions();
244 		assertThrowsWithMessage(Exception.class, "$R1", ()->s.build().serialize(r1));
245 
246 		s.ignoreRecursions();
247 		assertEquals("{name:'foo',r2:{name:'bar',r3:{name:'baz'}}}", s.build().serialize(r1));
248 
249 		// Make sure this doesn't blow up.
250 		s.build().getSchemaSerializer().serialize(r1);
251 	}
252 
253 	public static class R1 {
254 		public String name = "foo";
255 		public R2 r2;
256 	}
257 	public static class R2 {
258 		public String name = "bar";
259 		public R3 r3;
260 	}
261 	public static class R3 {
262 		public String name = "baz";
263 		public R1 r1;
264 	}
265 
266 	//====================================================================================================
267 	// Basic bean
268 	//====================================================================================================
269 	@Test void a09_basicBean() throws Exception {
270 		var s = JsonSerializer.create().json5().keepNullProperties().sortProperties().build();
271 
272 		var a = new J();
273 		a.setF1("J");
274 		a.setF2(100);
275 		a.setF3(true);
276 		assertEquals("{f1:'J',f2:100,f3:true}", s.serialize(a));
277 	}
278 
279 	public static class J {
280 		private String f1;
281 		public String getF1() { return f1; }
282 		public void setF1(String v) { f1 = v; }
283 
284 		private int f2 = -1;
285 		public int getF2() { return f2; }
286 		public void setF2(int v) { f2 = v; }
287 
288 		private boolean f3;
289 		public boolean isF3() { return f3; }
290 		public void setF3(boolean v) { f3 = v; }
291 
292 		@Override /* Object */
293 		public String toString() {
294 			return ("J(f1: " + this.getF1() + ", f2: " + this.getF2() + ")");
295 		}
296 	}
297 }