Skip to content

Commit ebe8e5a

Browse files
committed
Fix #1702: Gson.toJson creates CharSequence which does not implement toString
1 parent ceae88b commit ebe8e5a

File tree

2 files changed

+68
-11
lines changed

2 files changed

+68
-11
lines changed

gson/src/main/java/com/google/gson/internal/Streams.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ private static final class AppendableWriter extends Writer {
8989
}
9090

9191
@Override public void write(char[] chars, int offset, int length) throws IOException {
92-
currentWrite.chars = chars;
92+
currentWrite.setChars(chars);
9393
appendable.append(currentWrite, offset, offset + length);
9494
}
9595

@@ -103,18 +103,32 @@ private static final class AppendableWriter extends Writer {
103103
/**
104104
* A mutable char sequence pointing at a single char[].
105105
*/
106-
static class CurrentWrite implements CharSequence {
107-
char[] chars;
108-
public int length() {
106+
private static class CurrentWrite implements CharSequence {
107+
private char[] chars;
108+
private String cachedString;
109+
110+
public void setChars(char[] chars) {
111+
this.chars = chars;
112+
this.cachedString = null;
113+
}
114+
115+
@Override public int length() {
109116
return chars.length;
110117
}
111-
public char charAt(int i) {
118+
@Override public char charAt(int i) {
112119
return chars[i];
113120
}
114-
public CharSequence subSequence(int start, int end) {
121+
@Override public CharSequence subSequence(int start, int end) {
115122
return new String(chars, start, end - start);
116123
}
124+
125+
// Must return string representation to satisfy toString() contract
126+
@Override public String toString() {
127+
if (cachedString == null) {
128+
cachedString = new String(chars);
129+
}
130+
return cachedString;
131+
}
117132
}
118133
}
119-
120134
}

gson/src/test/java/com/google/gson/functional/ReadersWritersTest.java

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import com.google.gson.common.TestTypes.BagOfPrimitives;
2323

2424
import com.google.gson.reflect.TypeToken;
25+
26+
import java.util.Arrays;
2527
import java.util.Map;
2628
import junit.framework.TestCase;
2729

@@ -89,8 +91,8 @@ public void testTopLevelNullObjectDeserializationWithReaderAndSerializeNulls() {
8991
}
9092

9193
public void testReadWriteTwoStrings() throws IOException {
92-
Gson gson= new Gson();
93-
CharArrayWriter writer= new CharArrayWriter();
94+
Gson gson = new Gson();
95+
CharArrayWriter writer = new CharArrayWriter();
9496
writer.write(gson.toJson("one").toCharArray());
9597
writer.write(gson.toJson("two").toCharArray());
9698
CharArrayReader reader = new CharArrayReader(writer.toCharArray());
@@ -102,8 +104,8 @@ public void testReadWriteTwoStrings() throws IOException {
102104
}
103105

104106
public void testReadWriteTwoObjects() throws IOException {
105-
Gson gson= new Gson();
106-
CharArrayWriter writer= new CharArrayWriter();
107+
Gson gson = new Gson();
108+
CharArrayWriter writer = new CharArrayWriter();
107109
BagOfPrimitives expectedOne = new BagOfPrimitives(1, 1, true, "one");
108110
writer.write(gson.toJson(expectedOne).toCharArray());
109111
BagOfPrimitives expectedTwo = new BagOfPrimitives(2, 2, false, "two");
@@ -132,4 +134,45 @@ public void testTypeMismatchThrowsJsonSyntaxExceptionForReaders() {
132134
} catch (JsonSyntaxException expected) {
133135
}
134136
}
137+
138+
/**
139+
* Verifies that passing an {@link Appendable} which is not an instance of {@link Writer}
140+
* to {@code Gson.toJson} works correctly.
141+
*/
142+
public void testToJsonAppendable() {
143+
class CustomAppendable implements Appendable {
144+
final StringBuilder stringBuilder = new StringBuilder();
145+
146+
@Override
147+
public Appendable append(char c) throws IOException {
148+
stringBuilder.append(c);
149+
return this;
150+
}
151+
152+
@Override
153+
public Appendable append(CharSequence csq) throws IOException {
154+
if (csq == null) {
155+
append("null");
156+
} else {
157+
append(csq, 0, csq.length());
158+
}
159+
return this;
160+
}
161+
162+
public Appendable append(CharSequence csq, int start, int end) throws IOException {
163+
if (csq == null) {
164+
return append("null");
165+
}
166+
167+
// According to doc, toString() must return string representation
168+
String s = csq.toString();
169+
stringBuilder.append(s, start, end);
170+
return this;
171+
}
172+
}
173+
174+
CustomAppendable appendable = new CustomAppendable();
175+
gson.toJson(Arrays.asList("test", 123, true), appendable);
176+
assertEquals("[\"test\",123,true]", appendable.stringBuilder.toString());
177+
}
135178
}

0 commit comments

Comments
 (0)