mirror of
https://github.com/fankes/moshi.git
synced 2025-10-20 00:19:21 +08:00
Add JsonReader.skipName.
This commit is contained in:
@@ -68,7 +68,7 @@ internal class KotlinJsonAdapter<T>(
|
||||
val binding = if (index != -1) bindings[index] else null
|
||||
|
||||
if (binding == null) {
|
||||
reader.nextName()
|
||||
reader.skipName()
|
||||
reader.skipValue()
|
||||
continue
|
||||
}
|
||||
|
@@ -151,7 +151,7 @@ final class ClassJsonAdapter<T> extends JsonAdapter<T> {
|
||||
while (reader.hasNext()) {
|
||||
int index = reader.selectName(options);
|
||||
if (index == -1) {
|
||||
reader.nextName();
|
||||
reader.skipName();
|
||||
reader.skipValue();
|
||||
continue;
|
||||
}
|
||||
|
@@ -219,9 +219,9 @@ public abstract class JsonAdapter<T> {
|
||||
|
||||
/**
|
||||
* Returns a JSON adapter equal to this, but that throws a {@link JsonDataException} when
|
||||
* {@linkplain JsonReader#setFailOnUnknown(boolean) unknown values} are encountered. This
|
||||
* constraint applies to both the top-level message handled by this type adapter as well as to
|
||||
* nested messages.
|
||||
* {@linkplain JsonReader#setFailOnUnknown(boolean) unknown names and values} are encountered.
|
||||
* This constraint applies to both the top-level message handled by this type adapter as well as
|
||||
* to nested messages.
|
||||
*/
|
||||
@CheckReturnValue public final JsonAdapter<T> failOnUnknown() {
|
||||
final JsonAdapter<T> delegate = this;
|
||||
|
@@ -279,7 +279,7 @@ public abstract class JsonReader implements Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this parser forbids skipping values.
|
||||
* Returns true if this parser forbids skipping names and values.
|
||||
*/
|
||||
@CheckReturnValue public final boolean failOnUnknown() {
|
||||
return failOnUnknown;
|
||||
@@ -332,6 +332,15 @@ public abstract class JsonReader implements Closeable {
|
||||
*/
|
||||
public abstract int selectName(Options options) throws IOException;
|
||||
|
||||
/**
|
||||
* Skips the next token, consuming it. This method is intended for use when the JSON token stream
|
||||
* contains unrecognized or unhandled names.
|
||||
*
|
||||
* <p>This throws a {@link JsonDataException} if this parser has been configured to {@linkplain
|
||||
* #failOnUnknown fail on unknown} names.
|
||||
*/
|
||||
public abstract void skipName() throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the {@linkplain Token#STRING string} value of the next token, consuming it. If the next
|
||||
* token is a number, this method will return its string form.
|
||||
|
@@ -562,6 +562,27 @@ final class JsonUtf8Reader extends JsonReader {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override public void skipName() throws IOException {
|
||||
if (failOnUnknown) {
|
||||
throw new JsonDataException("Cannot skip unexpected " + peek() + " at " + getPath());
|
||||
}
|
||||
int p = peeked;
|
||||
if (p == PEEKED_NONE) {
|
||||
p = doPeek();
|
||||
}
|
||||
if (p == PEEKED_UNQUOTED_NAME) {
|
||||
skipUnquotedValue();
|
||||
} else if (p == PEEKED_DOUBLE_QUOTED_NAME) {
|
||||
skipQuotedValue(DOUBLE_QUOTE_OR_SLASH);
|
||||
} else if (p == PEEKED_SINGLE_QUOTED_NAME) {
|
||||
skipQuotedValue(SINGLE_QUOTE_OR_SLASH);
|
||||
} else if (p != PEEKED_BUFFERED_NAME) {
|
||||
throw new JsonDataException("Expected a name but was " + peek() + " at path " + getPath());
|
||||
}
|
||||
peeked = PEEKED_NONE;
|
||||
pathNames[stackSize - 1] = "null";
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@code name} is in {@code options} this consumes it and returns its index.
|
||||
* Otherwise this returns -1 and no name is consumed.
|
||||
|
@@ -151,6 +151,18 @@ final class JsonValueReader extends JsonReader {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override public void skipName() throws IOException {
|
||||
if (failOnUnknown) {
|
||||
throw new JsonDataException("Cannot skip unexpected " + peek() + " at " + getPath());
|
||||
}
|
||||
|
||||
Map.Entry<?, ?> peeked = require(Map.Entry.class, Token.NAME);
|
||||
|
||||
// Swap the Map.Entry for its value on the stack.
|
||||
stack[stackSize - 1] = peeked.getValue();
|
||||
pathNames[stackSize - 2] = "null";
|
||||
}
|
||||
|
||||
@Override public String nextString() throws IOException {
|
||||
Object peeked = (stackSize != 0 ? stack[stackSize - 1] : null);
|
||||
if (peeked instanceof String) {
|
||||
|
@@ -960,4 +960,23 @@ public final class JsonReaderTest {
|
||||
assertThat(value).isEqualTo(
|
||||
Collections.singletonMap("pizzas", Arrays.asList("cheese", "pepperoni")));
|
||||
}
|
||||
|
||||
@Test public void skipName() throws IOException {
|
||||
JsonReader reader = newReader("{\"a\":1}");
|
||||
reader.beginObject();
|
||||
reader.skipName();
|
||||
assertThat(reader.peek()).isEqualTo(JsonReader.Token.NUMBER);
|
||||
reader.skipValue();
|
||||
reader.endObject();
|
||||
}
|
||||
|
||||
@Test public void skipNameOnValueFails() throws IOException {
|
||||
JsonReader reader = newReader("1");
|
||||
try {
|
||||
reader.skipName();
|
||||
fail();
|
||||
} catch (JsonDataException expected) {
|
||||
}
|
||||
assertThat(reader.nextInt()).isEqualTo(1);
|
||||
}
|
||||
}
|
||||
|
@@ -994,6 +994,20 @@ public final class JsonUtf8ReaderTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void failureMessagePathFromSkipName() throws IOException {
|
||||
JsonReader reader = newReader("{\"a\":[42,}");
|
||||
reader.beginObject();
|
||||
reader.skipName();
|
||||
reader.beginArray();
|
||||
reader.nextInt();
|
||||
try {
|
||||
reader.peek();
|
||||
fail();
|
||||
} catch (JsonEncodingException expected) {
|
||||
assertThat(expected).hasMessage("Expected value at path $.null[1]");
|
||||
}
|
||||
}
|
||||
|
||||
@Test @Ignore public void strictVeryLongNumber() throws IOException {
|
||||
JsonReader reader = newReader("[0." + repeat('9', 8192) + "]");
|
||||
reader.beginArray();
|
||||
|
@@ -910,7 +910,7 @@ public final class MoshiTest {
|
||||
adapter.fromJson("{\"diameter\":5,\"crust\":\"thick\",\"extraCheese\":true}");
|
||||
fail();
|
||||
} catch (JsonDataException expected) {
|
||||
assertThat(expected).hasMessage("Cannot skip unexpected STRING at $.crust");
|
||||
assertThat(expected).hasMessage("Cannot skip unexpected NAME at $.diameter");
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user