This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-lang.git
The following commit(s) were added to refs/heads/master by this push: new 1dddec8 [LANG-1542] ToStringBuilder.reflectionToString - Wrong JSON format when object has a List/Array of Enum. 1dddec8 is described below commit 1dddec8ba867bc31233ba194f0753ea35818cbfd Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Wed Jun 24 09:26:11 2020 -0400 [LANG-1542] ToStringBuilder.reflectionToString - Wrong JSON format when object has a List/Array of Enum. --- src/changes/changes.xml | 1 + .../commons/lang3/builder/ToStringStyle.java | 51 ++++--- .../lang3/builder/JsonToStringStyleTest.java | 151 ++++++++++++++++++++- 3 files changed, 179 insertions(+), 24 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 8893683..7152b35 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -82,6 +82,7 @@ The <action> type attribute can be add,update,fix,remove. <action type="add" dev="ggregory">Add ImmutablePair factory methods left() and right().</action> <action type="add" dev="ggregory">Add ObjectUtils.toString(Object, Supplier<String>).</action> <action issue="LANG-1567" type="update" dev="ggregory" due-to="Miguel Muñoz, Bruno P. Kinoshita, Gary Gregory">Fixed Javadocs for setTestRecursive() #556.</action> + <action issue="LANG-1542" type="update" dev="ggregory" due-to=" Trần Ngọc Khoa, Gary Gregory">ToStringBuilder.reflectionToString - Wrong JSON format when object has a List of Enum.</action> </release> <release version="3.10" date="2020-03-22" description="New features and bug fixes. Requires Java 8, supports Java 9, 10, 11."> diff --git a/src/main/java/org/apache/commons/lang3/builder/ToStringStyle.java b/src/main/java/org/apache/commons/lang3/builder/ToStringStyle.java index 9b11573..4856c32 100644 --- a/src/main/java/org/apache/commons/lang3/builder/ToStringStyle.java +++ b/src/main/java/org/apache/commons/lang3/builder/ToStringStyle.java @@ -624,6 +624,16 @@ public abstract class ToStringStyle implements Serializable { * {@code toString}, not {@code null} */ protected void appendDetail(final StringBuffer buffer, final String fieldName, final Collection<?> coll) { + if (coll != null && !coll.isEmpty()) { + buffer.append(arrayStart); + int i = 0; + for (Object item : coll) { + appendDetail(buffer, fieldName, i++, item); + } + buffer.append(arrayEnd); + return; + } + buffer.append(coll); } @@ -919,20 +929,33 @@ public abstract class ToStringStyle implements Serializable { buffer.append(arrayStart); for (int i = 0; i < array.length; i++) { final Object item = array[i]; - if (i > 0) { - buffer.append(arraySeparator); - } - if (item == null) { - appendNullText(buffer, fieldName); - - } else { - appendInternal(buffer, fieldName, item, arrayContentDetail); - } + appendDetail(buffer, fieldName, i, item); } buffer.append(arrayEnd); } /** + * <p>Append to the {@code toString} the detail of an + * {@code Object} array item.</p> + * + * @param buffer the {@code StringBuffer} to populate + * @param fieldName the field name, typically not used as already appended + * @param i the array item index to add + * @param item the array item to add + * @since 3.11 + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, int i, final Object item) { + if (i > 0) { + buffer.append(arraySeparator); + } + if (item == null) { + appendNullText(buffer, fieldName); + } else { + appendInternal(buffer, fieldName, item, arrayContentDetail); + } + } + + /** * <p>Append to the {@code toString} the detail of an array type.</p> * * @param buffer the {@code StringBuffer} to populate @@ -946,15 +969,7 @@ public abstract class ToStringStyle implements Serializable { final int length = Array.getLength(array); for (int i = 0; i < length; i++) { final Object item = Array.get(array, i); - if (i > 0) { - buffer.append(arraySeparator); - } - if (item == null) { - appendNullText(buffer, fieldName); - - } else { - appendInternal(buffer, fieldName, item, arrayContentDetail); - } + appendDetail(buffer, fieldName, i, item); } buffer.append(arrayEnd); } diff --git a/src/test/java/org/apache/commons/lang3/builder/JsonToStringStyleTest.java b/src/test/java/org/apache/commons/lang3/builder/JsonToStringStyleTest.java index b0ad254..ed7bf34 100644 --- a/src/test/java/org/apache/commons/lang3/builder/JsonToStringStyleTest.java +++ b/src/test/java/org/apache/commons/lang3/builder/JsonToStringStyleTest.java @@ -16,17 +16,20 @@ */ package org.apache.commons.lang3.builder; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import org.apache.commons.lang3.builder.ToStringStyleTest.Person; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.List; -import org.apache.commons.lang3.builder.ToStringStyleTest.Person; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * Unit tests {@link org.apache.commons.lang3.builder.JsonToStringStyleTest}. @@ -182,6 +185,73 @@ public class JsonToStringStyleTest { } @Test + public void testList() { + Student student = new Student(); + ArrayList<Hobby> objects = new ArrayList<>(); + + objects.add(Hobby.BOOK); + objects.add(Hobby.SPORT); + objects.add(Hobby.MUSIC); + + student.setHobbies(objects); + + assertEquals(student.toString(), "{\"hobbies\":[\"BOOK\",\"SPORT\",\"MUSIC\"]}"); + student.setHobbies(new ArrayList<>()); + assertEquals(student.toString(), "{\"hobbies\":[]}"); + student.setHobbies(null); + assertEquals(student.toString(), "{\"hobbies\":null}"); + } + + @Test + public void testArrayEnum() { + Teacher teacher = new Teacher(); + Hobby[] hobbies = new Hobby[3]; + hobbies[0] = Hobby.BOOK; + hobbies[1] = Hobby.SPORT; + hobbies[2] = Hobby.MUSIC; + + teacher.setHobbies(hobbies); + + assertEquals(teacher.toString(), "{\"hobbies\":[\"BOOK\",\"SPORT\",\"MUSIC\"]}"); + teacher.setHobbies(new Hobby[0]); + assertEquals(teacher.toString(), "{\"hobbies\":[]}"); + teacher.setHobbies(null); + assertEquals(teacher.toString(), "{\"hobbies\":null}"); + } + + @Test + public void testCombineListAndEnum() { + Teacher teacher = new Teacher(); + + Hobby[] teacherHobbies = new Hobby[3]; + teacherHobbies[0] = Hobby.BOOK; + teacherHobbies[1] = Hobby.SPORT; + teacherHobbies[2] = Hobby.MUSIC; + + teacher.setHobbies(teacherHobbies); + + Student john = new Student(); + john.setHobbies(Arrays.asList(Hobby.BOOK, Hobby.MUSIC)); + + Student alice = new Student(); + alice.setHobbies(new ArrayList<>()); + + Student bob = new Student(); + bob.setHobbies(Collections.singletonList(Hobby.BOOK)); + + ArrayList<Student> students = new ArrayList<>(); + students.add(john); + students.add(alice); + students.add(bob); + + AcademyClass academyClass = new AcademyClass(); + academyClass.setStudents(students); + academyClass.setTeacher(teacher); + + assertEquals(academyClass.toString(), "{\"students\":[{\"hobbies\":[\"BOOK\",\"MUSIC\"]},{\"hobbies\":[]},{\"hobbies\":[\"BOOK\"]}],\"teacher\":{\"hobbies\":[\"BOOK\",\"SPORT\",\"MUSIC\"]}}"); + } + + @Test public void testPerson() { final Person p = new Person(); p.name = "Jane Doe"; @@ -477,4 +547,73 @@ public class JsonToStringStyleTest { */ Person person; } + + enum Hobby { + SPORT, + BOOK, + MUSIC + } + + enum EmptyEnum { + } + + static class Student { + List<Hobby> hobbies; + + public List<Hobby> getHobbies() { + return hobbies; + } + + public void setHobbies(List<Hobby> hobbies) { + this.hobbies = hobbies; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + } + + static class Teacher { + Hobby[] hobbies; + + public Hobby[] getHobbies() { + return hobbies; + } + + public void setHobbies(Hobby[] hobbies) { + this.hobbies = hobbies; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + } + + static class AcademyClass { + Teacher teacher; + List<Student> students; + + public void setTeacher(Teacher teacher) { + this.teacher = teacher; + } + + public void setStudents(List<Student> students) { + this.students = students; + } + + public Teacher getTeacher() { + return teacher; + } + + public List<Student> getStudents() { + return students; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + } }