diff --git a/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.java b/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.java index c0f7d2d..06b9652 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.java @@ -241,10 +241,6 @@ final class JsonUtf8Reader extends JsonReader { } private int doPeek() throws IOException { - if (valueSource != null) { - valueSource.discard(); - valueSource = null; - } int peekStack = scopes[stackSize - 1]; if (peekStack == JsonScope.EMPTY_ARRAY) { scopes[stackSize - 1] = JsonScope.NONEMPTY_ARRAY; @@ -329,6 +325,13 @@ final class JsonUtf8Reader extends JsonReader { } else { checkLenient(); } + } else if (peekStack == JsonScope.STREAMING_VALUE) { + valueSource.discard(); + valueSource = null; + stackSize--; + pathIndices[stackSize - 1]++; + pathNames[stackSize - 1] = "null"; + return doPeek(); } else if (peekStack == JsonScope.CLOSED) { throw new IllegalStateException("JsonReader is closed"); } @@ -1067,9 +1070,8 @@ final class JsonUtf8Reader extends JsonReader { } valueSource = new JsonValueSource(source, prefix, state, valueSourceStackSize); + pushScope(JsonScope.STREAMING_VALUE); peeked = PEEKED_NONE; - pathIndices[stackSize - 1]++; - pathNames[stackSize - 1] = "null"; return Okio.buffer(valueSource); } diff --git a/moshi/src/main/java/com/squareup/moshi/JsonValueSource.java b/moshi/src/main/java/com/squareup/moshi/JsonValueSource.java index 4bc895a..7f1f5ef 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonValueSource.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonValueSource.java @@ -76,7 +76,14 @@ final class JsonValueSource implements Source { } /** - * Advance {@link #limit} until it is at least {@code byteCount} or the JSON object is complete. + * Advance {@link #limit} until any of these conditions are met: + * + *
Because we don't have a slow stream in this test, we just add bytes to our underlying stream + * immediately before they're needed. + */ + @Test + public void nextSourceStreams() throws IOException { + Buffer stream = new Buffer(); + stream.writeUtf8("[\""); + + JsonReader reader = JsonReader.of(Okio.buffer((Source) stream)); + reader.beginArray(); + BufferedSource source = reader.nextSource(); + assertThat(source.readUtf8(1)).isEqualTo("\""); + stream.writeUtf8("hello"); + assertThat(source.readUtf8(5)).isEqualTo("hello"); + stream.writeUtf8("world"); + assertThat(source.readUtf8(5)).isEqualTo("world"); + stream.writeUtf8("\""); + assertThat(source.readUtf8(1)).isEqualTo("\""); + stream.writeUtf8("]"); + assertThat(source.exhausted()).isTrue(); + reader.endArray(); + } + + @Test + public void nextSourceObjectAfterSelect() throws IOException { + // language=JSON + JsonReader reader = newReader("[\"p\u0065psi\"]"); + reader.beginArray(); + assertThat(reader.selectName(JsonReader.Options.of("coke"))).isEqualTo(-1); + try (BufferedSource valueSource = reader.nextSource()) { + assertThat(valueSource.readUtf8()).isEqualTo("\"pepsi\""); // not the original characters! + } + } + + @Test + public void nextSourceObjectAfterPromoteNameToValue() throws IOException { + // language=JSON + JsonReader reader = newReader("{\"a\":true}"); + reader.beginObject(); + reader.promoteNameToValue(); + try (BufferedSource valueSource = reader.nextSource()) { + assertThat(valueSource.readUtf8()).isEqualTo("\"a\""); + } + assertThat(reader.nextBoolean()).isEqualTo(true); + reader.endObject(); + } + + @Test + public void nextSourcePath() throws IOException { + // language=JSON + JsonReader reader = newReader("{\"a\":true,\"b\":[],\"c\":false}"); + reader.beginObject(); + + assertThat(reader.nextName()).isEqualTo("a"); + assertThat(reader.getPath()).isEqualTo("$.a"); + assertThat(reader.nextBoolean()).isTrue(); + assertThat(reader.getPath()).isEqualTo("$.a"); + + assertThat(reader.nextName()).isEqualTo("b"); + try (BufferedSource valueSource = reader.nextSource()) { + assertThat(reader.getPath()).isEqualTo("$.b"); + assertThat(valueSource.readUtf8()).isEqualTo("[]"); + } + assertThat(reader.getPath()).isEqualTo("$.b"); + + assertThat(reader.nextName()).isEqualTo("c"); + assertThat(reader.getPath()).isEqualTo("$.c"); + assertThat(reader.nextBoolean()).isFalse(); + assertThat(reader.getPath()).isEqualTo("$.c"); + reader.endObject(); + } }