Skip to content

Commit 8ec1e5e

Browse files
committed
Fix #2187
1 parent 85f384a commit 8ec1e5e

File tree

16 files changed

+116
-95
lines changed

16 files changed

+116
-95
lines changed

release-notes/VERSION-2.x

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Project: jackson-databind
1515
(requested by Édouard M)
1616
#2126: `DeserializationContext.instantiationException()` throws `InvalidDefinitionException`
1717
#2153: Add `JsonMapper` to replace generic `ObjectMapper` usage
18+
#2187: Make `JsonNode.toString()` use shared `ObjectMapper` to produce valid json
1819

1920
2.9.8 (not yet released)
2021

src/main/java/com/fasterxml/jackson/databind/JsonNode.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -947,10 +947,10 @@ public boolean equals(Comparator<JsonNode> comparator, JsonNode other) {
947947
*/
948948

949949
/**
950-
* Method that will produce developer-readable representation of the
951-
* node; which may <b>or may not</b> be as valid JSON.
952-
* If you want valid JSON output (or output formatted using one of
953-
* other Jackson supported data formats) make sure to use
950+
* Method that will produce (as of Jackson 2.10) valid JSON using
951+
* default settings of databind, as String.
952+
* If you want other kinds of JSON output (or output formatted using one of
953+
* other Jackson-supported data formats) make sure to use
954954
* {@link ObjectMapper} or {@link ObjectWriter} to serialize an
955955
* instance, for example:
956956
*<pre>
@@ -964,6 +964,16 @@ public boolean equals(Comparator<JsonNode> comparator, JsonNode other) {
964964
@Override
965965
public abstract String toString();
966966

967+
/**
968+
* Alternative to {@link #toString} that will serialize this node using
969+
* Jackson default pretty-printer.
970+
*
971+
* @since 2.10
972+
*/
973+
public String toPrettyString() {
974+
return toString();
975+
}
976+
967977
/**
968978
* Equality for node objects is defined as full (deep) value
969979
* equality. This means that it is possible to compare complete

src/main/java/com/fasterxml/jackson/databind/node/ArrayNode.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -839,21 +839,6 @@ public int hashCode() {
839839
return _children.hashCode();
840840
}
841841

842-
@Override
843-
public String toString()
844-
{
845-
StringBuilder sb = new StringBuilder(16 + (size() << 4));
846-
sb.append('[');
847-
for (int i = 0, len = _children.size(); i < len; ++i) {
848-
if (i > 0) {
849-
sb.append(',');
850-
}
851-
sb.append(_children.get(i).toString());
852-
}
853-
sb.append(']');
854-
return sb.toString();
855-
}
856-
857842
/*
858843
/**********************************************************
859844
/* Internal methods (overridable)

src/main/java/com/fasterxml/jackson/databind/node/BaseJsonNode.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,5 +97,21 @@ public abstract void serialize(JsonGenerator jgen, SerializerProvider provider)
9797
public abstract void serializeWithType(JsonGenerator jgen, SerializerProvider provider,
9898
TypeSerializer typeSer)
9999
throws IOException, JsonProcessingException;
100+
101+
/*
102+
/**********************************************************
103+
/* Std method overrides
104+
/**********************************************************
105+
*/
106+
107+
@Override
108+
public final String toString() {
109+
return InternalNodeMapper.nodeToString(this);
110+
}
111+
112+
@Override
113+
public final String toPrettyString() {
114+
return InternalNodeMapper.nodeToPrettyString(this);
115+
}
100116
}
101117

src/main/java/com/fasterxml/jackson/databind/node/BinaryNode.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,4 @@ public boolean equals(Object o)
110110
public int hashCode() {
111111
return (_data == null) ? -1 : _data.length;
112112
}
113-
114-
/**
115-
* Different from other values, since contents need to be surrounded
116-
* by (double) quotes.
117-
*/
118-
@Override
119-
public String toString()
120-
{
121-
return Base64Variants.getDefaultVariant().encode(_data, true);
122-
}
123113
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.fasterxml.jackson.databind.node;
2+
3+
import java.io.IOException;
4+
5+
import com.fasterxml.jackson.databind.JsonNode;
6+
import com.fasterxml.jackson.databind.ObjectWriter;
7+
import com.fasterxml.jackson.databind.json.JsonMapper;
8+
9+
/**
10+
* Helper class used to implement <code>toString()</code> method for
11+
* {@link BaseJsonNode}, by embedding a private instance of
12+
* {@link JsonMapper}, only to be used for node serialization.
13+
*
14+
* @since 2.10 (but not to be included in 3.0)
15+
*/
16+
final class InternalNodeMapper {
17+
private final static JsonMapper JSON_MAPPER = new JsonMapper();
18+
private final static ObjectWriter STD_WRITER = JSON_MAPPER.writer();
19+
private final static ObjectWriter PRETTY_WRITER = JSON_MAPPER.writer()
20+
.withDefaultPrettyPrinter();
21+
22+
public static String nodeToString(JsonNode n) {
23+
try {
24+
return STD_WRITER.writeValueAsString(n);
25+
} catch (IOException e) { // should never occur
26+
throw new RuntimeException(e);
27+
}
28+
}
29+
30+
public static String nodeToPrettyString(JsonNode n) {
31+
try {
32+
return PRETTY_WRITER.writeValueAsString(n);
33+
} catch (IOException e) { // should never occur
34+
throw new RuntimeException(e);
35+
}
36+
}
37+
}

src/main/java/com/fasterxml/jackson/databind/node/MissingNode.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,6 @@ public boolean equals(Object o)
9898
return (o == this);
9999
}
100100

101-
@Override
102-
public String toString() {
103-
// toString() should never return null
104-
return "";
105-
}
106-
107101
@Override
108102
public int hashCode() {
109103
return JsonNodeType.MISSING.ordinal();

src/main/java/com/fasterxml/jackson/databind/node/ObjectNode.java

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -852,25 +852,6 @@ public int hashCode()
852852
return _children.hashCode();
853853
}
854854

855-
@Override
856-
public String toString()
857-
{
858-
StringBuilder sb = new StringBuilder(32 + (size() << 4));
859-
sb.append("{");
860-
int count = 0;
861-
for (Map.Entry<String, JsonNode> en : _children.entrySet()) {
862-
if (count > 0) {
863-
sb.append(",");
864-
}
865-
++count;
866-
TextNode.appendQuoted(sb, en.getKey());
867-
sb.append(':');
868-
sb.append(en.getValue().toString());
869-
}
870-
sb.append("}");
871-
return sb.toString();
872-
}
873-
874855
/*
875856
/**********************************************************
876857
/* Internal methods (overridable)

src/main/java/com/fasterxml/jackson/databind/node/POJONode.java

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import com.fasterxml.jackson.core.*;
66
import com.fasterxml.jackson.databind.JsonSerializable;
77
import com.fasterxml.jackson.databind.SerializerProvider;
8-
import com.fasterxml.jackson.databind.util.RawValue;
98

109
/**
1110
* Value node that contains a wrapped POJO, to be serialized as
@@ -156,17 +155,4 @@ protected boolean _pojoEquals(POJONode other)
156155

157156
@Override
158157
public int hashCode() { return _value.hashCode(); }
159-
160-
@Override
161-
public String toString()
162-
{
163-
// [databind#743]: Let's try indicating content type, for debugging purposes
164-
if (_value instanceof byte[]) {
165-
return String.format("(binary value of %d bytes)", ((byte[]) _value).length);
166-
}
167-
if (_value instanceof RawValue) {
168-
return String.format("(raw value '%s')", ((RawValue) _value).toString());
169-
}
170-
return String.valueOf(_value);
171-
}
172158
}

src/main/java/com/fasterxml/jackson/databind/node/TextNode.java

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -164,19 +164,7 @@ public boolean equals(Object o)
164164
@Override
165165
public int hashCode() { return _value.hashCode(); }
166166

167-
/**
168-
* Different from other values, Strings need quoting
169-
*/
170-
@Override
171-
public String toString()
172-
{
173-
int len = _value.length();
174-
len = len + 2 + (len >> 4);
175-
StringBuilder sb = new StringBuilder(len);
176-
appendQuoted(sb, _value);
177-
return sb.toString();
178-
}
179-
167+
@Deprecated // since 2.10
180168
protected static void appendQuoted(StringBuilder sb, String content)
181169
{
182170
sb.append('"');

src/main/java/com/fasterxml/jackson/databind/node/ValueNode.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,6 @@ public void serializeWithType(JsonGenerator g, SerializerProvider provider,
4747
typeSer.writeTypeSuffix(g, typeIdDef);
4848
}
4949

50-
/*
51-
/**********************************************************************
52-
/* Base impls for standard methods
53-
/**********************************************************************
54-
*/
55-
56-
@Override
57-
public String toString() { return asText(); }
58-
5950
/*
6051
**********************************************************************
6152
* Navigation methods

src/test/java/com/fasterxml/jackson/databind/jsontype/deftyping/TestDefaultForArrays.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.fasterxml.jackson.annotation.JsonTypeInfo;
99
import com.fasterxml.jackson.databind.*;
1010
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
11+
import com.fasterxml.jackson.databind.node.ObjectNode;
1112

1213
public class TestDefaultForArrays extends BaseMapTest
1314
{
@@ -95,7 +96,11 @@ public void testNodeInEmptyArray() throws Exception {
9596
Object[] obs = new Object[] { node };
9697
json = m.writeValueAsString(obs);
9798
Object[] result = m.readValue(json, Object[].class);
98-
assertEquals("{}", result[0].toString());
99+
100+
assertEquals(1, result.length);
101+
Object elem = result[0];
102+
assertTrue(elem instanceof ObjectNode);
103+
assertEquals(0, ((ObjectNode) elem).size());
99104
}
100105

101106
public void testArraysOfArrays() throws Exception

src/test/java/com/fasterxml/jackson/databind/node/ObjectNodeTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,6 @@ public void testInvalidWithArray() throws Exception
328328
}
329329
}
330330

331-
// [Issue#93]
332331
public void testSetAll() throws Exception
333332
{
334333
ObjectNode root = MAPPER.createObjectNode();

src/test/java/com/fasterxml/jackson/databind/node/TestJsonNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ public void testPOJO()
8383
assertStandardEquals(n);
8484
assertEquals(n, new POJONode("x"));
8585
assertEquals("x", n.asText());
86-
// not sure if this is what it'll remain as but:
87-
assertEquals("x", n.toString());
86+
// 10-Dec-2018, tatu: With 2.10, should serialize same as via ObjectMapper/ObjectWriter
87+
assertEquals("\"x\"", n.toString());
8888

8989
assertEquals(new POJONode(null), new POJONode(null));
9090

src/test/java/com/fasterxml/jackson/databind/node/TestMissingNode.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ public void testMissing()
1515
assertEquals(JsonToken.NOT_AVAILABLE, n.asToken());
1616
assertEquals("", n.asText());
1717
assertStandardEquals(n);
18-
assertEquals("", n.toString());
18+
// 10-Dec-2018, tatu: With 2.10, should serialize same as via ObjectMapper/ObjectWriter
19+
assertEquals("null", n.toString());
1920

2021
assertNodeNumbersForNonNumeric(n);
2122

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.fasterxml.jackson.databind.node;
2+
3+
import com.fasterxml.jackson.databind.*;
4+
5+
public class ToStringForNodesTest extends BaseMapTest
6+
{
7+
private final ObjectMapper MAPPER = objectMapper();
8+
9+
public void testObjectNode() throws Exception
10+
{
11+
_verifyToStrings(MAPPER.readTree("{ \"key\" : 1, \"b\" : \"x\", \"array\" : [ 1, false ] }"));
12+
final ObjectNode n = MAPPER.createObjectNode().put("msg", "hello world");
13+
assertEquals("{\"msg\":\"hello world\"}", n.toString());
14+
assertEquals("{\n \"msg\" : \"hello world\"\n}", n.toPrettyString());
15+
}
16+
17+
public void testArrayNode() throws Exception
18+
{
19+
_verifyToStrings(MAPPER.readTree("[ 1, true, null, [ \"abc\",3], { } ]"));
20+
final ArrayNode n = MAPPER.createArrayNode().add(0.25).add(true);
21+
assertEquals("[0.25,true]", n.toString());
22+
assertEquals("[ 0.25, true ]", n.toPrettyString());
23+
}
24+
25+
public void testBinaryNode() throws Exception
26+
{
27+
_verifyToStrings(MAPPER.getNodeFactory().binaryNode(new byte[] { 1, 2, 3, 4, 6 }));
28+
}
29+
30+
protected void _verifyToStrings(JsonNode node) throws Exception
31+
{
32+
assertEquals(MAPPER.writeValueAsString(node), node.toString());
33+
34+
assertEquals(MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(node),
35+
node.toPrettyString());
36+
}
37+
}

0 commit comments

Comments
 (0)