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.AbstractLangTest;
32 import org.apache.commons.lang3.builder.ToStringStyleTest.Person;
33 import org.junit.jupiter.api.AfterEach;
34 import org.junit.jupiter.api.BeforeEach;
35 import org.junit.jupiter.api.Test;
36
37
38
39
40 class JsonToStringStyleTest extends AbstractLangTest {
41
42 static class AcademyClass {
43 Teacher teacher;
44 List<Student> students;
45
46 public List<Student> getStudents() {
47 return students;
48 }
49
50 public Teacher getTeacher() {
51 return teacher;
52 }
53
54 public void setStudents(final List<Student> students) {
55 this.students = students;
56 }
57
58 public void setTeacher(final Teacher teacher) {
59 this.teacher = teacher;
60 }
61
62 @Override
63 public String toString() {
64 return ToStringBuilder.reflectionToString(this);
65 }
66 }
67
68 enum EmptyEnum {
69 }
70
71 enum Hobby {
72 SPORT,
73 BOOK,
74 MUSIC
75 }
76
77
78
79
80 static class InnerMapObject {
81
82
83
84
85 String pid;
86
87
88
89
90 Map<String, Object> map;
91 }
92
93
94
95
96 static class NestingPerson {
97
98
99
100
101 String pid;
102
103
104
105
106 Person person;
107 }
108
109 static class Student {
110 List<Hobby> hobbies;
111
112 public List<Hobby> getHobbies() {
113 return hobbies;
114 }
115
116 public void setHobbies(final List<Hobby> hobbies) {
117 this.hobbies = hobbies;
118 }
119
120 @Override
121 public String toString() {
122 return ToStringBuilder.reflectionToString(this);
123 }
124 }
125
126 static class Teacher {
127 Hobby[] hobbies;
128
129 public Hobby[] getHobbies() {
130 return hobbies;
131 }
132
133 public void setHobbies(final Hobby[] hobbies) {
134 this.hobbies = hobbies;
135 }
136
137 @Override
138 public String toString() {
139 return ToStringBuilder.reflectionToString(this);
140 }
141 }
142
143 private final Integer base = Integer.valueOf(5);
144
145 @BeforeEach
146 public void setUp() {
147 ToStringBuilder.setDefaultStyle(ToStringStyle.JSON_STYLE);
148 }
149
150 @AfterEach
151 public void tearDown() {
152 ToStringBuilder.setDefaultStyle(ToStringStyle.DEFAULT_STYLE);
153 }
154
155 @Test
156 void testAppendSuper() {
157 assertEquals(
158 "{}",
159 new ToStringBuilder(base).appendSuper(
160 "Integer@8888[" + System.lineSeparator() + "]")
161 .toString());
162 assertEquals(
163 "{}",
164 new ToStringBuilder(base).appendSuper(
165 "Integer@8888[" + System.lineSeparator() + " null"
166 + System.lineSeparator() + "]").toString());
167 assertEquals(
168 "{\"a\":\"hello\"}",
169 new ToStringBuilder(base)
170 .appendSuper(
171 "Integer@8888[" + System.lineSeparator()
172 + "]").append("a", "hello").toString());
173 assertEquals(
174 "{\"a\":\"hello\"}",
175 new ToStringBuilder(base)
176 .appendSuper(
177 "Integer@8888[" + System.lineSeparator()
178 + " null" + System.lineSeparator()
179 + "]").append("a", "hello").toString());
180 assertEquals("{\"a\":\"hello\"}", new ToStringBuilder(base)
181 .appendSuper(null).append("a", "hello").toString());
182
183 assertEquals("{\"a\":\"hello\",\"b\":\"world\"}", new ToStringBuilder(base)
184 .appendSuper("{\"a\":\"hello\"}").append("b", "world").toString());
185 }
186
187 @Test
188 void testArray() {
189 final Person p = new Person();
190 p.name = "Jane Doe";
191 p.age = 25;
192 p.smoker = true;
193
194 assertEquals(
195 "{\"name\":\"Jane Doe\",\"age\":25,\"smoker\":true,\"groups\":['admin', 'manager', 'user']}",
196 new ToStringBuilder(p).append("name", p.name)
197 .append("age", p.age).append("smoker", p.smoker)
198 .append("groups", new Object() {
199 @Override
200 public String toString() {
201 return "['admin', 'manager', 'user']";
202 }
203 })
204 .toString());
205 }
206
207 @Test
208 void testArrayEnum() {
209 final Teacher teacher = new Teacher();
210 final Hobby[] hobbies = new Hobby[3];
211 hobbies[0] = Hobby.BOOK;
212 hobbies[1] = Hobby.SPORT;
213 hobbies[2] = Hobby.MUSIC;
214
215 teacher.setHobbies(hobbies);
216
217 assertEquals(teacher.toString(), "{\"hobbies\":[\"BOOK\",\"SPORT\",\"MUSIC\"]}");
218 teacher.setHobbies(new Hobby[0]);
219 assertEquals(teacher.toString(), "{\"hobbies\":[]}");
220 teacher.setHobbies(null);
221 assertEquals(teacher.toString(), "{\"hobbies\":null}");
222 }
223
224 @Test
225 void testBlank() {
226 assertEquals("{}", new ToStringBuilder(base).toString());
227 }
228
229 @Test
230 void testBooleanArray() {
231 final boolean[] array = { true, false };
232 final ToStringBuilder toStringBuilder = new ToStringBuilder(base);
233 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append(array).toString());
234 assertEquals("{\"booleanArray\":[true,false]}", toStringBuilder.append("booleanArray", array).toString());
235 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
236 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((long[]) null).toString());
237 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
238 }
239
240 @Test
241 void testByteArray() {
242 final byte[] array = { 1, 2, -3, 4 };
243 final ToStringBuilder toStringBuilder = new ToStringBuilder(base);
244 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append(array).toString());
245 assertEquals("{\"byteArray\":[1,2,-3,4]}", toStringBuilder.append("byteArray", array).toString());
246 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
247 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((long[]) null).toString());
248 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
249 }
250
251 @Test
252 void testChar() {
253 assertThrows(UnsupportedOperationException.class, () -> new ToStringBuilder(base).append('A').toString());
254 assertEquals("{\"a\":\"A\"}", new ToStringBuilder(base).append("a", 'A').toString());
255 assertEquals("{\"a\":\"A\",\"b\":\"B\"}", new ToStringBuilder(base).append("a", 'A').append("b", 'B').toString());
256 }
257
258 @Test
259 void testCharArray() {
260 final char[] array = { '1', '2', '3', '4' };
261 final ToStringBuilder toStringBuilder = new ToStringBuilder(base);
262 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append(array).toString());
263 assertEquals("{\"charArray\":[\"1\",\"2\",\"3\",\"4\"]}", toStringBuilder.append("charArray", array).toString());
264 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
265 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((long[]) null).toString());
266 assertThrows(UnsupportedOperationException.class, () -> toStringBuilder.append((Object) array).toString());
267 }
268
269 @Test
270 void testCombineListAndEnum() {
271 final Teacher teacher = new Teacher();
272
273 final Hobby[] teacherHobbies = new Hobby[3];
274 teacherHobbies[0] = Hobby.BOOK;
275 teacherHobbies[1] = Hobby.SPORT;
276 teacherHobbies[2] = Hobby.MUSIC;
277
278 teacher.setHobbies(teacherHobbies);
279
280 final Student john = new Student();
281 john.setHobbies(Arrays.asList(Hobby.BOOK, Hobby.MUSIC));
282
283 final Student alice = new Student();
284 alice.setHobbies(new ArrayList<>());
285
286 final Student bob = new Student();
287 bob.setHobbies(Collections.singletonList(Hobby.BOOK));
288
289 final ArrayList<Student> students = new ArrayList<>();
290 students.add(john);
291 students.add(alice);
292 students.add(bob);
293
294 final AcademyClass academyClass = new AcademyClass();
295 academyClass.setStudents(students);
296 academyClass.setTeacher(teacher);
297
298 assertEquals(academyClass.toString(), "{\"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 assertEquals(student.toString(), "{\"hobbies\":[\"BOOK\",\"SPORT\",\"MUSIC\"]}");
372 student.setHobbies(new ArrayList<>());
373 assertEquals(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 }