You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2020/06/24 13:26:19 UTC

[commons-lang] branch master updated: [LANG-1542] ToStringBuilder.reflectionToString - Wrong JSON format when object has a List/Array of Enum.

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 <ga...@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&lt;String&gt;).</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);
+        }
+    }
 }