[LANG-1542] ToStringBuilder.reflectionToString - Wrong JSON format when

object has a List/Array of Enum.
This commit is contained in:
Gary Gregory 2020-06-24 09:26:11 -04:00
parent deb5f817af
commit 1dddec8ba8
3 changed files with 180 additions and 25 deletions

View File

@ -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 ImmutablePair factory methods left() and right().</action>
<action type="add" dev="ggregory">Add ObjectUtils.toString(Object, Supplier&lt;String&gt;).</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-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>
<release version="3.10" date="2020-03-22" description="New features and bug fixes. Requires Java 8, supports Java 9, 10, 11."> <release version="3.10" date="2020-03-22" description="New features and bug fixes. Requires Java 8, supports Java 9, 10, 11.">

View File

@ -624,6 +624,16 @@ protected void appendDetail(final StringBuffer buffer, final String fieldName, f
* {@code toString}, not {@code null} * {@code toString}, not {@code null}
*/ */
protected void appendDetail(final StringBuffer buffer, final String fieldName, final Collection<?> coll) { 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); buffer.append(coll);
} }
@ -919,18 +929,31 @@ protected void appendDetail(final StringBuffer buffer, final String fieldName, f
buffer.append(arrayStart); buffer.append(arrayStart);
for (int i = 0; i < array.length; i++) { for (int i = 0; i < array.length; i++) {
final Object item = array[i]; final Object item = array[i];
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) { if (i > 0) {
buffer.append(arraySeparator); buffer.append(arraySeparator);
} }
if (item == null) { if (item == null) {
appendNullText(buffer, fieldName); appendNullText(buffer, fieldName);
} else { } else {
appendInternal(buffer, fieldName, item, arrayContentDetail); appendInternal(buffer, fieldName, item, arrayContentDetail);
} }
} }
buffer.append(arrayEnd);
}
/** /**
* <p>Append to the {@code toString} the detail of an array type.</p> * <p>Append to the {@code toString} the detail of an array type.</p>
@ -946,15 +969,7 @@ protected void reflectionAppendArrayDetail(final StringBuffer buffer, final Stri
final int length = Array.getLength(array); final int length = Array.getLength(array);
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
final Object item = Array.get(array, i); final Object item = Array.get(array, i);
if (i > 0) { appendDetail(buffer, fieldName, i, item);
buffer.append(arraySeparator);
}
if (item == null) {
appendNullText(buffer, fieldName);
} else {
appendInternal(buffer, fieldName, item, arrayContentDetail);
}
} }
buffer.append(arrayEnd); buffer.append(arrayEnd);
} }

View File

@ -16,18 +16,21 @@
*/ */
package org.apache.commons.lang3.builder; package org.apache.commons.lang3.builder;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import org.apache.commons.lang3.builder.ToStringStyleTest.Person; import org.apache.commons.lang3.builder.ToStringStyleTest.Person;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; 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 static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
/** /**
* Unit tests {@link org.apache.commons.lang3.builder.JsonToStringStyleTest}. * Unit tests {@link org.apache.commons.lang3.builder.JsonToStringStyleTest}.
*/ */
@ -181,6 +184,73 @@ public void testObject() {
.toString()); .toString());
} }
@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 @Test
public void testPerson() { public void testPerson() {
final Person p = new Person(); final Person p = new Person();
@ -477,4 +547,73 @@ static class NestingPerson {
*/ */
Person person; 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);
}
}
} }