diff --git a/gson/src/main/java/com/google/gson/internal/Streams.java b/gson/src/main/java/com/google/gson/internal/Streams.java index ac99910a97..84ae633dcf 100644 --- a/gson/src/main/java/com/google/gson/internal/Streams.java +++ b/gson/src/main/java/com/google/gson/internal/Streams.java @@ -89,7 +89,7 @@ private static final class AppendableWriter extends Writer { } @Override public void write(char[] chars, int offset, int length) throws IOException { - currentWrite.chars = chars; + currentWrite.setChars(chars); appendable.append(currentWrite, offset, offset + length); } @@ -103,18 +103,32 @@ private static final class AppendableWriter extends Writer { /** * A mutable char sequence pointing at a single char[]. */ - static class CurrentWrite implements CharSequence { - char[] chars; - public int length() { + private static class CurrentWrite implements CharSequence { + private char[] chars; + private String cachedString; + + public void setChars(char[] chars) { + this.chars = chars; + this.cachedString = null; + } + + @Override public int length() { return chars.length; } - public char charAt(int i) { + @Override public char charAt(int i) { return chars[i]; } - public CharSequence subSequence(int start, int end) { + @Override public CharSequence subSequence(int start, int end) { return new String(chars, start, end - start); } + + // Must return string representation to satisfy toString() contract + @Override public String toString() { + if (cachedString == null) { + cachedString = new String(chars); + } + return cachedString; + } } } - } diff --git a/gson/src/test/java/com/google/gson/functional/ReadersWritersTest.java b/gson/src/test/java/com/google/gson/functional/ReadersWritersTest.java index e21fb903e4..e9b860941f 100644 --- a/gson/src/test/java/com/google/gson/functional/ReadersWritersTest.java +++ b/gson/src/test/java/com/google/gson/functional/ReadersWritersTest.java @@ -22,6 +22,8 @@ import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.reflect.TypeToken; + +import java.util.Arrays; import java.util.Map; import junit.framework.TestCase; @@ -89,8 +91,8 @@ public void testTopLevelNullObjectDeserializationWithReaderAndSerializeNulls() { } public void testReadWriteTwoStrings() throws IOException { - Gson gson= new Gson(); - CharArrayWriter writer= new CharArrayWriter(); + Gson gson = new Gson(); + CharArrayWriter writer = new CharArrayWriter(); writer.write(gson.toJson("one").toCharArray()); writer.write(gson.toJson("two").toCharArray()); CharArrayReader reader = new CharArrayReader(writer.toCharArray()); @@ -102,8 +104,8 @@ public void testReadWriteTwoStrings() throws IOException { } public void testReadWriteTwoObjects() throws IOException { - Gson gson= new Gson(); - CharArrayWriter writer= new CharArrayWriter(); + Gson gson = new Gson(); + CharArrayWriter writer = new CharArrayWriter(); BagOfPrimitives expectedOne = new BagOfPrimitives(1, 1, true, "one"); writer.write(gson.toJson(expectedOne).toCharArray()); BagOfPrimitives expectedTwo = new BagOfPrimitives(2, 2, false, "two"); @@ -132,4 +134,45 @@ public void testTypeMismatchThrowsJsonSyntaxExceptionForReaders() { } catch (JsonSyntaxException expected) { } } + + /** + * Verifies that passing an {@link Appendable} which is not an instance of {@link Writer} + * to {@code Gson.toJson} works correctly. + */ + public void testToJsonAppendable() { + class CustomAppendable implements Appendable { + final StringBuilder stringBuilder = new StringBuilder(); + + @Override + public Appendable append(char c) throws IOException { + stringBuilder.append(c); + return this; + } + + @Override + public Appendable append(CharSequence csq) throws IOException { + if (csq == null) { + append("null"); + } else { + append(csq, 0, csq.length()); + } + return this; + } + + public Appendable append(CharSequence csq, int start, int end) throws IOException { + if (csq == null) { + return append("null"); + } + + // According to doc, toString() must return string representation + String s = csq.toString(); + stringBuilder.append(s, start, end); + return this; + } + } + + CustomAppendable appendable = new CustomAppendable(); + gson.toJson(Arrays.asList("test", 123, true), appendable); + assertEquals("[\"test\",123,true]", appendable.stringBuilder.toString()); + } }