[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 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-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="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>
|
||||
|
|
|
@ -19,7 +19,10 @@ package org.apache.commons.lang3.builder;
|
|||
import java.io.Serializable;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
|
@ -2595,6 +2598,37 @@ public abstract class ToStringStyle implements Serializable {
|
|||
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) {
|
||||
return valueAsString.startsWith(getArrayStart())
|
||||
&& valueAsString.endsWith(getArrayEnd());
|
||||
|
|
|
@ -26,6 +26,8 @@ import java.util.Date;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.lang3.builder.ToStringStyleTest.Person;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
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());
|
||||
}
|
||||
|
||||
@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}.
|
||||
*
|
||||
|
@ -616,4 +682,20 @@ public class JsonToStringStyleTest {
|
|||
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