1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.lang3.builder;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertThrows;
21
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.Date;
26 import java.util.HashMap;
27 import java.util.LinkedHashMap;
28 import java.util.List;
29 import java.util.Map;
30
31 import org.apache.commons.lang3.builder.ToStringStyleTest.Person;
32 import org.junit.jupiter.api.AfterEach;
33 import org.junit.jupiter.api.BeforeEach;
34 import org.junit.jupiter.api.Test;
35
36
37
38
39 class JsonToStringStyleTest extends AbstractBuilderTest {
40
41 static class AcademyClass {
42 Teacher teacher;
43 List<Student> students;
44
45 public List<Student> getStudents() {
46 return students;
47 }
48
49 public Teacher getTeacher() {
50 return teacher;
51 }
52
53 public void setStudents(final List<Student> students) {
54 this.students = students;
55 }
56
57 public void setTeacher(final Teacher teacher) {
58 this.teacher = teacher;
59 }
60
61 @Override
62 public String toString() {
63 return ToStringBuilder.reflectionToString(this);
64 }
65 }
66
67 enum EmptyEnum {
68 }
69
70 enum Hobby {
71 SPORT,
72 BOOK,
73 MUSIC
74 }
75
76
77
78
79 static class InnerMapObject {
80
81
82
83
84 String pid;
85
86
87
88
89 Map<String, Object> map;
90 }
91
92
93
94
95 static class NestingPerson {
96
97
98
99
100 String pid;
101
102
103
104
105 Person person;
106 }
107
108 static class Student {
109 List<Hobby> hobbies;
110
111 public List<Hobby> getHobbies() {
112 return hobbies;
113 }
114
115 public void setHobbies(final List<Hobby> hobbies) {
116 this.hobbies = hobbies;
117 }
118
119 @Override
120 public String toString() {
121 return ToStringBuilder.reflectionToString(this);
122 }
123 }
124
125 static class Teacher {
126 Hobby[] hobbies;
127
128 public Hobby[] getHobbies() {
129 return hobbies;
130 }
131
132 public void setHobbies(final Hobby[] hobbies) {
133 this.hobbies = hobbies;
134 }
135
136 @Override
137 public String toString() {
138 return ToStringBuilder.reflectionToString(this);
139 }
140 }
141
142 private final Integer base = Integer.valueOf(5);
143
144 @BeforeEach
145 public void setUp() {
146 ToStringBuilder.setDefaultStyle(ToStringStyle.JSON_STYLE);
147 }
148
149 @AfterEach
150 public void tearDown() {
151 ToStringBuilder.setDefaultStyle(ToStringStyle.DEFAULT_STYLE);
152 }
153
154 @Test
155 void testAppendSuper() {
156 assertEquals(
157 "{}",
158 new ToStringBuilder(base).appendSuper(
159 "Integer@8888[" + System.lineSeparator() + "]")
160 .toString());
161 assertEquals(
162 "{}",
163 new ToStringBuilder(base).appendSuper(
164 "Integer@8888[" + System.lineSeparator() + " null"
165 + System.lineSeparator() + "]").toString());
166 assertEquals(
167 "{\"a\":\"hello\"}",
168 new ToStringBuilder(base)
169 .appendSuper(
170 "Integer@8888[" + System.lineSeparator()
171 + "]").append("a", "hello").toString());
172 assertEquals(
173 "{\"a\":\"hello\"}",
174 new ToStringBuilder(base)
175 .appendSuper(
176 "Integer@8888[" + System.lineSeparator()
177 + " null" + System.lineSeparator()
178 + "]").append("a", "hello").toString());
179 assertEquals("{\"a\":\"hello\"}", new ToStringBuilder(base)
180 .appendSuper(null).append("a", "hello").toString());
181
182 assertEquals("{\"a\":\"hello\",\"b\":\"world\"}", new ToStringBuilder(base)
183 .appendSuper("{\"a\":\"hello\"}").append("b", "world").toString());
184 }
185
186 @Test
187 void testArray() {
188 final Person p = new Person();
189 p.name = "Jane Doe";
190 p.age = 25;
191 p.smoker = true;
192
193 assertEquals(
194 "{\"name\":\"Jane Doe\",\"age\":25,\"smoker\":true,\"groups\":['admin', 'manager', 'user']}",
195 new ToStringBuilder(p).append("name", p.name)
196 .append("age", p.age).append("smoker", p.smoker)
197 .append("groups", new Object() {
198 @Override
199 public String toString() {
200 return "['admin', 'manager', 'user']";
201 }
202 })
203 .toString());
204 }
205
206 @Test
207 void testArrayEnum() {
208 final Teacher teacher = new Teacher();
209 final Hobby[] hobbies = new Hobby[3];
210 hobbies[0] = Hobby.BOOK;
211 hobbies[1] = Hobby.SPORT;
212 hobbies[2] = Hobby.MUSIC;
213
214 teacher.setHobbies(hobbies);
215
216 assertEqualsIfAccessible(teacher.toString(), "{\"hobbies\":[\"BOOK\",\"SPORT\",\"MUSIC\"]}");
217 teacher.setHobbies(new Hobby[0]);
218 assertEqualsIfAccessible(teacher.toString(), "{\"hobbies\":[]}");
219 teacher.setHobbies(null);
220 assertEquals(teacher.toString(), "{\"hobbies\":null}");
221 }
222
223 @Test
224 void testBlank() {
225 assertEquals("{}", new ToStringBuilder(base).toString());
226 }
227
228 @Test
229 void testBooleanArray() {
230 final boolean[] array = { true, false };
231 final ToStringBuilder toStringBuilder = new ToStringBuilder(base);
232 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append(array).toString());
233 assertEquals("{\"booleanArray\":[true,false]}", toStringBuilder.append("booleanArray", array).toString());
234 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
235 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((long[]) null).toString());
236 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
237 }
238
239 @Test
240 void testByteArray() {
241 final byte[] array = { 1, 2, -3, 4 };
242 final ToStringBuilder toStringBuilder = new ToStringBuilder(base);
243 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append(array).toString());
244 assertEquals("{\"byteArray\":[1,2,-3,4]}", toStringBuilder.append("byteArray", array).toString());
245 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
246 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((long[]) null).toString());
247 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
248 }
249
250 @Test
251 void testChar() {
252 assertThrows(UnsupportedOperationException.class, () -> new ToStringBuilder(base).append('A').toString());
253 assertEquals("{\"a\":\"A\"}", new ToStringBuilder(base).append("a", 'A').toString());
254 assertEquals("{\"a\":\"A\",\"b\":\"B\"}", new ToStringBuilder(base).append("a", 'A').append("b", 'B').toString());
255 }
256
257 @Test
258 void testCharArray() {
259 final char[] array = { '1', '2', '3', '4' };
260 final ToStringBuilder toStringBuilder = new ToStringBuilder(base);
261 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append(array).toString());
262 assertEquals("{\"charArray\":[\"1\",\"2\",\"3\",\"4\"]}", toStringBuilder.append("charArray", array).toString());
263 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
264 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((long[]) null).toString());
265 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
266 }
267
268 @Test
269 void testCombineListAndEnum() {
270 final Teacher teacher = new Teacher();
271
272 final Hobby[] teacherHobbies = new Hobby[3];
273 teacherHobbies[0] = Hobby.BOOK;
274 teacherHobbies[1] = Hobby.SPORT;
275 teacherHobbies[2] = Hobby.MUSIC;
276
277 teacher.setHobbies(teacherHobbies);
278
279 final Student john = new Student();
280 john.setHobbies(Arrays.asList(Hobby.BOOK, Hobby.MUSIC));
281
282 final Student alice = new Student();
283 alice.setHobbies(new ArrayList<>());
284
285 final Student bob = new Student();
286 bob.setHobbies(Collections.singletonList(Hobby.BOOK));
287
288 final ArrayList<Student> students = new ArrayList<>();
289 students.add(john);
290 students.add(alice);
291 students.add(bob);
292
293 final AcademyClass academyClass = new AcademyClass();
294 academyClass.setStudents(students);
295 academyClass.setTeacher(teacher);
296
297 assertEqualsIfAccessible(academyClass.toString(),
298 "{\"students\":[{\"hobbies\":[\"BOOK\",\"MUSIC\"]},{\"hobbies\":[]},{\"hobbies\":[\"BOOK\"]}],\"teacher\":{\"hobbies\":[\"BOOK\",\"SPORT\",\"MUSIC\"]}}");
299 }
300
301 @Test
302 void testDate() {
303 final Date now = new Date();
304 final Date afterNow = new Date(System.currentTimeMillis() + 1);
305
306 assertThrows(UnsupportedOperationException.class, () -> new ToStringBuilder(base).append(now).toString());
307
308 assertEquals("{\"now\":\"" + now + "\"}", new ToStringBuilder(base).append("now", now).toString());
309 assertEquals("{\"now\":\"" + now + "\",\"after\":\"" + afterNow + "\"}",
310 new ToStringBuilder(base).append("now", now).append("after", afterNow).toString());
311 }
312
313 @Test
314 void testDoubleArray() {
315 final double[] array = { 1, 2, -3, 4 };
316 final ToStringBuilder toStringBuilder = new ToStringBuilder(base);
317 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append(array).toString());
318 assertEquals("{\"doubleArray\":[1.0,2.0,-3.0,4.0]}", toStringBuilder.append("doubleArray", array).toString());
319 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
320 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((long[]) null).toString());
321 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
322 }
323
324 @Test
325 void testFloatArray() {
326 final float[] array = { 1, 2, -3, 4 };
327 final ToStringBuilder toStringBuilder = new ToStringBuilder(base);
328 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append(array).toString());
329 assertEquals("{\"floatArray\":[1.0,2.0,-3.0,4.0]}", toStringBuilder.append("floatArray", array).toString());
330 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
331 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((long[]) null).toString());
332 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
333 }
334
335 @Test
336 void testIntArray() {
337 final int[] array = { 1, 2, -3, 4 };
338 final ToStringBuilder toStringBuilder = new ToStringBuilder(base);
339 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append(array).toString());
340 assertEquals("{\"intArray\":[1,2,-3,4]}", toStringBuilder.append("intArray", array).toString());
341 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
342 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((long[]) null).toString());
343 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
344 }
345
346 @Test
347 void testLANG1395() {
348 assertEquals("{\"name\":\"value\"}", new ToStringBuilder(base).append("name", "value").toString());
349 assertEquals("{\"name\":\"\"}", new ToStringBuilder(base).append("name", "").toString());
350 assertEquals("{\"name\":\"\\\"\"}", new ToStringBuilder(base).append("name", '"').toString());
351 assertEquals("{\"name\":\"\\\\\"}", new ToStringBuilder(base).append("name", '\\').toString());
352 assertEquals("{\"name\":\"Let's \\\"quote\\\" this\"}", new ToStringBuilder(base).append("name", "Let's \"quote\" this").toString());
353 }
354
355 @Test
356 void testLANG1396() {
357 assertEquals("{\"Let's \\\"quote\\\" this\":\"value\"}", new ToStringBuilder(base).append("Let's \"quote\" this", "value").toString());
358 }
359
360 @Test
361 void testList() {
362 final Student student = new Student();
363 final ArrayList<Hobby> objects = new ArrayList<>();
364
365 objects.add(Hobby.BOOK);
366 objects.add(Hobby.SPORT);
367 objects.add(Hobby.MUSIC);
368
369 student.setHobbies(objects);
370
371 assertEqualsIfAccessible(student.toString(), "{\"hobbies\":[\"BOOK\",\"SPORT\",\"MUSIC\"]}");
372 student.setHobbies(new ArrayList<>());
373 assertEqualsIfAccessible(student.toString(), "{\"hobbies\":[]}");
374 student.setHobbies(null);
375 assertEquals(student.toString(), "{\"hobbies\":null}");
376 }
377
378 @Test
379 void testLong() {
380 assertThrows(UnsupportedOperationException.class, () -> new ToStringBuilder(base).append(3L).toString());
381
382 assertEquals("{\"a\":3}", new ToStringBuilder(base).append("a", 3L)
383 .toString());
384 assertEquals("{\"a\":3,\"b\":4}",
385 new ToStringBuilder(base).append("a", 3L).append("b", 4L)
386 .toString());
387 }
388
389 @Test
390 void testLongArray() {
391 final long[] array = { 1, 2, -3, 4 };
392 final ToStringBuilder toStringBuilder = new ToStringBuilder(base);
393 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append(array).toString());
394 assertEquals("{\"longArray\":[1,2,-3,4]}", toStringBuilder.append("longArray", array).toString());
395 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
396 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((long[]) null).toString());
397 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
398 }
399
400 @Test
401 void testLongArrayArray() {
402 final long[][] array = { { 1, 2 }, null, { 5 } };
403 final ToStringBuilder toStringBuilder = new ToStringBuilder(base);
404 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append(array).toString());
405 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
406 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((long[][]) null).toString());
407 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
408 }
409
410 @Test
411 void testMapSkipNullKey() {
412 final Map<String, Object> map = new LinkedHashMap<>();
413 map.put("k1", "v1");
414 map.put(null, "v2");
415
416 assertEquals("{\"map\":{\"k1\":\"v1\"}}",
417 new ToStringBuilder(base).append("map", map).toString());
418 }
419
420 @Test
421 void testNestedMaps() {
422 final Map<String, Object> innerMap = new LinkedHashMap<>();
423 innerMap.put("k2.1", "v2.1");
424 innerMap.put("k2.2", "v2.2");
425 final Map<String, Object> baseMap = new LinkedHashMap<>();
426 baseMap.put("k1", "v1");
427 baseMap.put("k2", innerMap);
428
429 final InnerMapObject object = new InnerMapObject() {
430 @Override
431 public String toString() {
432 return new ToStringBuilder(this).append("pid", this.pid).append("map", this.map).toString();
433 }
434 };
435 object.pid = "dummy-text";
436 object.map = baseMap;
437
438 assertEquals("{\"object\":{\"pid\":\"dummy-text\",\"map\":{\"k1\":\"v1\",\"k2\":{\"k2.1\":\"v2.1\",\"k2.2\":\"v2.2\"}}}}",
439 new ToStringBuilder(base).append("object", object).toString());
440 }
441
442 @Test
443 void testNestingPerson() {
444 final Person p = new Person() {
445 @Override
446 public String toString() {
447 return new ToStringBuilder(this).append("name", this.name).append("age", this.age).append("smoker", this.smoker).toString();
448 }
449 };
450 p.name = "Jane Doe";
451 p.age = 25;
452 p.smoker = true;
453
454 final NestingPerson nestP = new NestingPerson();
455 nestP.pid = "#1@Jane";
456 nestP.person = p;
457
458 assertEquals("{\"pid\":\"#1@Jane\",\"person\":{\"name\":\"Jane Doe\",\"age\":25,\"smoker\":true}}",
459 new ToStringBuilder(nestP).append("pid", nestP.pid).append("person", nestP.person).toString());
460 }
461
462 @Test
463 void testNull() {
464 assertEquals("null", new ToStringBuilder(null).toString());
465 }
466
467 @Test
468 void testObject() {
469 final Integer i3 = Integer.valueOf(3);
470 final Integer i4 = Integer.valueOf(4);
471 assertThrows(UnsupportedOperationException.class, () -> new ToStringBuilder(base).append((Object) null).toString());
472 assertThrows(UnsupportedOperationException.class, () -> new ToStringBuilder(base).append(i3).toString());
473 assertEquals("{\"a\":null}", new ToStringBuilder(base).append("a", (Object) null).toString());
474 assertEquals("{\"a\":3}", new ToStringBuilder(base).append("a", i3).toString());
475 assertEquals("{\"a\":3,\"b\":4}", new ToStringBuilder(base).append("a", i3).append("b", i4).toString());
476 assertThrows(UnsupportedOperationException.class, () -> new ToStringBuilder(base).append("a", i3, false).toString());
477 assertThrows(UnsupportedOperationException.class, () -> new ToStringBuilder(base).append("a", new ArrayList<>(), false).toString());
478 assertEquals("{\"a\":[]}", new ToStringBuilder(base).append("a", new ArrayList<>(), true).toString());
479 assertThrows(UnsupportedOperationException.class, () -> new ToStringBuilder(base).append("a", new HashMap<>(), false).toString());
480 assertEquals("{\"a\":{}}", new ToStringBuilder(base).append("a", new HashMap<>(), true).toString());
481 assertThrows(UnsupportedOperationException.class, () -> new ToStringBuilder(base).append("a", (Object) new String[0], false).toString());
482 assertEquals("{\"a\":[]}", new ToStringBuilder(base).append("a", (Object) new String[0], true).toString());
483 assertThrows(UnsupportedOperationException.class, () -> new ToStringBuilder(base).append("a", (Object) new int[] { 1, 2, 3 }, false).toString());
484 assertEquals("{\"a\":[1,2,3]}", new ToStringBuilder(base).append("a", (Object) new int[] { 1, 2, 3 }, true).toString());
485 assertThrows(UnsupportedOperationException.class,
486 () -> new ToStringBuilder(base).append("a", (Object) new String[] { "v", "x", "y", "z" }, false).toString());
487 assertEquals("{\"a\":[\"v\",\"x\",\"y\",\"z\"]}", new ToStringBuilder(base).append("a", (Object) new String[] { "v", "x", "y", "z" }, true).toString());
488 }
489
490 @Test
491 void testObjectArray() {
492 final Object[] array = { null, base, new int[] { 3, 6 } };
493 final ToStringBuilder toStringBuilder = new ToStringBuilder(base);
494 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append(array).toString());
495 assertEquals("{\"objectArray\":[null,5,[3,6]]}", toStringBuilder.append("objectArray", array).toString());
496 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
497 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object[]) null).toString());
498 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
499 }
500
501 @Test
502 void testObjectWithInnerMap() {
503 final Map<String, Object> map = new LinkedHashMap<>();
504 map.put("k1", "value1");
505 map.put("k2", 2);
506
507 final InnerMapObject object = new InnerMapObject() {
508 @Override
509 public String toString() {
510 return new ToStringBuilder(this).append("pid", this.pid).append("map", this.map).toString();
511 }
512 };
513 object.pid = "dummy-text";
514 object.map = map;
515
516 assertEquals("{\"object\":{\"pid\":\"dummy-text\",\"map\":{\"k1\":\"value1\",\"k2\":2}}}",
517 new ToStringBuilder(base).append("object", object).toString());
518 }
519
520 @Test
521 void testPerson() {
522 final Person p = new Person();
523 p.name = "Jane Doe";
524 p.age = 25;
525 p.smoker = true;
526
527 assertEquals(
528 "{\"name\":\"Jane Doe\",\"age\":25,\"smoker\":true}",
529 new ToStringBuilder(p).append("name", p.name)
530 .append("age", p.age).append("smoker", p.smoker)
531 .toString());
532 }
533
534 @Test
535 void testRootMap() {
536 final Map<String, Object> map = new LinkedHashMap<>();
537 map.put("k1", "v1");
538 map.put("k2", 2);
539
540 assertEquals("{\"map\":{\"k1\":\"v1\",\"k2\":2}}",
541 new ToStringBuilder(base).append("map", map).toString());
542 }
543
544 @Test
545 void testShortArray() {
546 final short[] array = { 1, 2, -3, 4 };
547 final ToStringBuilder toStringBuilder = new ToStringBuilder(base);
548 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append(array).toString());
549 assertEquals("{\"shortArray\":[1,2,-3,4]}", toStringBuilder.append("shortArray", array).toString());
550 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
551 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((long[]) null).toString());
552 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
553 }
554 }