Repository: netty/netty
Issue: JsonObjectDecoder to better handle streaming data
Labels: defect

### Description
There seems to be a long running issue with several iterations of fixes for streaming of different types of JSON data:
- The [6156](https://github.com/netty/netty/issues/6156) was the original issue which made the internal index reset together with resetting the decoder state, but it did not cover the case with streaming arrays.
- The [6969](https://github.com/netty/netty/issues/6969) fixed the problem with arrays, but did not cover the case with streaming objects.
- The [7722](https://github.com/netty/netty/issues/7722) is a (currently) opened issue which fixes the problem with streaming objects. While the described solution seems to workaround the problem, it causes multiple reads of the same bytes and technically does not fully recover the state (different branches are executed for the repeated reads).

A better approach seems to be to just properly recover the internal decoder index given the information about how far the decoder went from the readerIndex and the last readerIndex are already there which seems to cover both the cases with streaming arrays and objects.

### Netty version
4.1.22.Final

Issue comments:

Pull request review comments:

Patch that resolved the issue:
diff --git a/codec/src/main/java/io/netty/handler/codec/json/JsonObjectDecoder.java b/codec/src/main/java/io/netty/handler/codec/json/JsonObjectDecoder.java
index 123618b1437..f63e62066ee 100644
--- a/codec/src/main/java/io/netty/handler/codec/json/JsonObjectDecoder.java
+++ b/codec/src/main/java/io/netty/handler/codec/json/JsonObjectDecoder.java
@@ -91,11 +91,7 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) t
         }
 
         if (this.idx > in.readerIndex() && lastReaderIndex != in.readerIndex()) {
-            this.idx = in.readerIndex();
-            if (state == ST_DECODING_ARRAY_STREAM) {
-                insideString = false;
-                openBraces = 1;
-            }
+            this.idx = in.readerIndex() + (idx - lastReaderIndex);
         }
 
         // index of next byte to process.


Test patch:
diff --git a/codec/src/test/java/io/netty/handler/codec/json/JsonObjectDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/json/JsonObjectDecoderTest.java
index 12eb13ac19c..d29654f2491 100644
--- a/codec/src/test/java/io/netty/handler/codec/json/JsonObjectDecoderTest.java
+++ b/codec/src/test/java/io/netty/handler/codec/json/JsonObjectDecoderTest.java
@@ -47,6 +47,27 @@ public void testJsonObjectOverMultipleWrites() {
         assertFalse(ch.finish());
     }
 
+    @Test
+    public void testMultipleJsonObjectsOverMultipleWrites() {
+        EmbeddedChannel ch = new EmbeddedChannel(new JsonObjectDecoder());
+
+        String objectPart1 = "{\"name\":\"Jo";
+        String objectPart2 = "hn\"}{\"name\":\"John\"}{\"name\":\"Jo";
+        String objectPart3 = "hn\"}";
+
+        ch.writeInbound(Unpooled.copiedBuffer(objectPart1, CharsetUtil.UTF_8));
+        ch.writeInbound(Unpooled.copiedBuffer(objectPart2, CharsetUtil.UTF_8));
+        ch.writeInbound(Unpooled.copiedBuffer(objectPart3, CharsetUtil.UTF_8));
+
+        for (int i = 0; i < 3; i++) {
+            ByteBuf res = ch.readInbound();
+            assertEquals("{\"name\":\"John\"}", res.toString(CharsetUtil.UTF_8));
+            res.release();
+        }
+
+        assertFalse(ch.finish());
+    }
+
     @Test
     public void testJsonArrayOverMultipleWrites() {
         EmbeddedChannel ch = new EmbeddedChannel(new JsonObjectDecoder());