From 5f2513a407793b4f9d5293f77414144e76041087 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Sun, 31 Jul 2022 23:46:43 +0200 Subject: [PATCH] Improve AppendableWriter performance (#1706) * Improve AppendableWriter performance Override methods which by default create char arrays or convert CharSequences to Strings. This is not necessary for AppendableWriter because it can directly append these values to the Appendable delegate. * Add test for Streams.writerForAppendable --- .../com/google/gson/internal/Streams.java | 23 ++++++- .../com/google/gson/internal/StreamsTest.java | 68 +++++++++++++++++++ 2 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 gson/src/test/java/com/google/gson/internal/StreamsTest.java 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 0bb73aa18e..1fc6839baa 100644 --- a/gson/src/main/java/com/google/gson/internal/Streams.java +++ b/gson/src/main/java/com/google/gson/internal/Streams.java @@ -93,12 +93,31 @@ private static final class AppendableWriter extends Writer { appendable.append(currentWrite, offset, offset + length); } + @Override public void flush() {} + @Override public void close() {} + + // Override these methods for better performance + // They would otherwise unnecessarily create Strings or char arrays + @Override public void write(int i) throws IOException { appendable.append((char) i); } - @Override public void flush() {} - @Override public void close() {} + @Override public void write(String str, int off, int len) throws IOException { + // Appendable.append turns null -> "null", which is not desired here + $Gson$Preconditions.checkNotNull(str); + appendable.append(str, off, off + len); + } + + @Override public Writer append(CharSequence csq) throws IOException { + appendable.append(csq); + return this; + } + + @Override public Writer append(CharSequence csq, int start, int end) throws IOException { + appendable.append(csq, start, end); + return this; + } /** * A mutable char sequence pointing at a single char[]. diff --git a/gson/src/test/java/com/google/gson/internal/StreamsTest.java b/gson/src/test/java/com/google/gson/internal/StreamsTest.java new file mode 100644 index 0000000000..d0cb90aa5b --- /dev/null +++ b/gson/src/test/java/com/google/gson/internal/StreamsTest.java @@ -0,0 +1,68 @@ +package com.google.gson.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.io.Writer; +import org.junit.Test; + +public class StreamsTest { + @Test + public void testWriterForAppendable() throws IOException { + StringBuilder stringBuilder = new StringBuilder(); + Writer writer = Streams.writerForAppendable(stringBuilder); + + writer.append('a'); + writer.append('\u1234'); + writer.append("test"); + writer.append(null); // test custom null handling mandated by `append` + writer.append("abcdef", 2, 4); + writer.append(null, 1, 3); // test custom null handling mandated by `append` + writer.append(','); + + writer.write('a'); + writer.write('\u1234'); + // Should only consider the 16 low-order bits + writer.write(0x4321_1234); + writer.append(','); + + writer.write("chars".toCharArray()); + try { + writer.write((char[]) null); + fail(); + } catch (NullPointerException e) { + } + + writer.write("chars".toCharArray(), 1, 2); + try { + writer.write((char[]) null, 1, 2); + fail(); + } catch (NullPointerException e) { + } + writer.append(','); + + writer.write("string"); + try { + writer.write((String) null); + fail(); + } catch (NullPointerException e) { + } + + writer.write("string", 1, 2); + try { + writer.write((String) null, 1, 2); + fail(); + } catch (NullPointerException e) { + } + + String actualOutput = stringBuilder.toString(); + assertEquals("a\u1234testnullcdul,a\u1234\u1234,charsha,stringtr", actualOutput); + + writer.flush(); + writer.close(); + + // flush() and close() calls should have had no effect + assertEquals(actualOutput, stringBuilder.toString()); + } +}