From 4fef636977ecef910783ec01d6a3e2b3acff6275 Mon Sep 17 00:00:00 2001
From: Marcono1234 <Marcono1234@users.noreply.github.com>
Date: Sat, 23 May 2020 16:55:04 +0200
Subject: [PATCH 1/2] 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.
---
 .../com/google/gson/internal/Streams.java     | 23 +++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

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..bc5b9c5165 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[].

From d2ec70b544c74665330fae6f3d6218121334a131 Mon Sep 17 00:00:00 2001
From: Marcono1234 <Marcono1234@users.noreply.github.com>
Date: Sat, 30 Jul 2022 00:31:16 +0200
Subject: [PATCH 2/2] Add test for Streams.writerForAppendable

---
 .../com/google/gson/internal/StreamsTest.java | 68 +++++++++++++++++++
 1 file changed, 68 insertions(+)
 create mode 100644 gson/src/test/java/com/google/gson/internal/StreamsTest.java

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());
+  }
+}