[LANG-1543] [JSON string for maps] ToStringBuilder.reflectionToString
doesnt render nested maps correctly. Apply a different version of the PR https://github.com/apache/commons-lang/pull/561 Closes #561.
This commit is contained in:
parent
062bc6fe7d
commit
4063df71c3
|
@ -81,6 +81,7 @@ The <action> type attribute can be add,update,fix,remove.
|
||||||
<action type="add" dev="ggregory">Add ObjectUtils.toString(Object, Supplier<String>).</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-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>
|
<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>
|
||||||
|
<action issue="LANG-1543" type="fix" dev="ggregory" due-to="Swaraj Pal, Gary Gregory">[JSON string for maps] ToStringBuilder.reflectionToString doesnt render nested maps correctly.</action>
|
||||||
<action type="update" dev="ggregory">Make org.apache.commons.lang3.CharSequenceUtils.toCharArray(CharSequence) public.</action>
|
<action type="update" dev="ggregory">Make org.apache.commons.lang3.CharSequenceUtils.toCharArray(CharSequence) public.</action>
|
||||||
<action type="add" dev="ggregory">Add org.apache.commons.lang3.StringUtils.substringAfter(String, int).</action>
|
<action type="add" dev="ggregory">Add org.apache.commons.lang3.StringUtils.substringAfter(String, int).</action>
|
||||||
<action type="add" dev="ggregory">Add org.apache.commons.lang3.StringUtils.substringAfterLast(String, int).</action>
|
<action type="add" dev="ggregory">Add org.apache.commons.lang3.StringUtils.substringAfterLast(String, int).</action>
|
||||||
|
|
|
@ -19,7 +19,10 @@ package org.apache.commons.lang3.builder;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ClassUtils;
|
import org.apache.commons.lang3.ClassUtils;
|
||||||
|
@ -2595,6 +2598,37 @@ public abstract class ToStringStyle implements Serializable {
|
||||||
appendDetail(buffer, fieldName, valueAsString);
|
appendDetail(buffer, fieldName, valueAsString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendDetail(final StringBuffer buffer, final String fieldName, final Map<?, ?> map) {
|
||||||
|
if (map != null && !map.isEmpty()) {
|
||||||
|
buffer.append(getContentStart());
|
||||||
|
|
||||||
|
boolean firstItem = true;
|
||||||
|
for (final Entry<?, ?> entry : map.entrySet()) {
|
||||||
|
final String keyStr = Objects.toString(entry.getKey(), null);
|
||||||
|
if (keyStr != null) {
|
||||||
|
if (firstItem) {
|
||||||
|
firstItem = false;
|
||||||
|
} else {
|
||||||
|
appendFieldEnd(buffer, keyStr);
|
||||||
|
}
|
||||||
|
appendFieldStart(buffer, keyStr);
|
||||||
|
final Object value = entry.getValue();
|
||||||
|
if (value == null) {
|
||||||
|
appendNullText(buffer, keyStr);
|
||||||
|
} else {
|
||||||
|
appendInternal(buffer, keyStr, value, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.append(getContentEnd());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.append(map);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isJsonArray(final String valueAsString) {
|
private boolean isJsonArray(final String valueAsString) {
|
||||||
return valueAsString.startsWith(getArrayStart())
|
return valueAsString.startsWith(getArrayStart())
|
||||||
&& valueAsString.endsWith(getArrayEnd());
|
&& valueAsString.endsWith(getArrayEnd());
|
||||||
|
|
|
@ -26,6 +26,8 @@ import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
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;
|
||||||
|
@ -532,6 +534,70 @@ public class JsonToStringStyleTest {
|
||||||
assertEquals("{\"Let's \\\"quote\\\" this\":\"value\"}", new ToStringBuilder(base).append("Let's \"quote\" this", "value").toString());
|
assertEquals("{\"Let's \\\"quote\\\" this\":\"value\"}", new ToStringBuilder(base).append("Let's \"quote\" this", "value").toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRootMap() {
|
||||||
|
final Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
map.put("k1", "v1");
|
||||||
|
map.put("k2", 2);
|
||||||
|
|
||||||
|
assertEquals("{\"map\":{\"k1\":\"v1\",\"k2\":2}}",
|
||||||
|
new ToStringBuilder(base).append("map", map).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testObjectWithInnerMap() {
|
||||||
|
final Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
map.put("k1", "value1");
|
||||||
|
map.put("k2", 2);
|
||||||
|
|
||||||
|
final InnerMapObject object = new InnerMapObject(){
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new ToStringBuilder(this).append("pid", this.pid)
|
||||||
|
.append("map", this.map).toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
object.pid = "dummy-text";
|
||||||
|
object.map = map;
|
||||||
|
|
||||||
|
assertEquals("{\"object\":{\"pid\":\"dummy-text\",\"map\":{\"k1\":\"value1\",\"k2\":2}}}",
|
||||||
|
new ToStringBuilder(base).append("object", object).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNestedMaps() {
|
||||||
|
final Map<String, Object> innerMap = new LinkedHashMap<>();
|
||||||
|
innerMap.put("k2.1", "v2.1");
|
||||||
|
innerMap.put("k2.2", "v2.2");
|
||||||
|
final Map<String, Object> baseMap = new LinkedHashMap<>();
|
||||||
|
baseMap.put("k1", "v1");
|
||||||
|
baseMap.put("k2", innerMap);
|
||||||
|
|
||||||
|
final InnerMapObject object = new InnerMapObject(){
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new ToStringBuilder(this).append("pid", this.pid)
|
||||||
|
.append("map", this.map).toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
object.pid = "dummy-text";
|
||||||
|
object.map = baseMap;
|
||||||
|
|
||||||
|
assertEquals("{\"object\":{\"pid\":\"dummy-text\",\"map\":{\"k1\":\"v1\"," +
|
||||||
|
"\"k2\":{\"k2.1\":\"v2.1\",\"k2.2\":\"v2.2\"}}}}",
|
||||||
|
new ToStringBuilder(base).append("object", object).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMapSkipNullKey() {
|
||||||
|
final Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
map.put("k1", "v1");
|
||||||
|
map.put(null, "v2");
|
||||||
|
|
||||||
|
assertEquals("{\"map\":{\"k1\":\"v1\"}}",
|
||||||
|
new ToStringBuilder(base).append("map", map).toString());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object with nested object structures used to test {@link ToStringStyle.JsonToStringStyle}.
|
* An object with nested object structures used to test {@link ToStringStyle.JsonToStringStyle}.
|
||||||
*
|
*
|
||||||
|
@ -616,4 +682,20 @@ public class JsonToStringStyleTest {
|
||||||
return ToStringBuilder.reflectionToString(this);
|
return ToStringBuilder.reflectionToString(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object with a Map field used to test {@link ToStringStyle.JsonToStringStyle}.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static class InnerMapObject {
|
||||||
|
/**
|
||||||
|
* Test String field.
|
||||||
|
*/
|
||||||
|
String pid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test inner map field.
|
||||||
|
*/
|
||||||
|
Map<String, Object> map;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue