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