mirror of
https://github.com/fankes/moshi.git
synced 2025-10-20 00:19:21 +08:00
JsonAdapter.fromJson(String) must fully consume. (#441)
* JsonAdapter.fromJson(String) must fully consume. * Replace field with method.
This commit is contained in:
committed by
Jesse Wilson
parent
aede26d5e1
commit
ed1ea5a755
@@ -37,7 +37,12 @@ public abstract class JsonAdapter<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@CheckReturnValue public final @Nullable T fromJson(String string) throws IOException {
|
@CheckReturnValue public final @Nullable T fromJson(String string) throws IOException {
|
||||||
return fromJson(new Buffer().writeUtf8(string));
|
JsonReader reader = JsonReader.of(new Buffer().writeUtf8(string));
|
||||||
|
T result = fromJson(reader);
|
||||||
|
if (!isLenient() && reader.peek() != JsonReader.Token.END_DOCUMENT) {
|
||||||
|
throw new JsonDataException("JSON document was not fully consumed.");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void toJson(JsonWriter writer, @Nullable T value) throws IOException;
|
public abstract void toJson(JsonWriter writer, @Nullable T value) throws IOException;
|
||||||
@@ -109,6 +114,9 @@ public abstract class JsonAdapter<T> {
|
|||||||
writer.setSerializeNulls(serializeNulls);
|
writer.setSerializeNulls(serializeNulls);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Override boolean isLenient() {
|
||||||
|
return delegate.isLenient();
|
||||||
|
}
|
||||||
@Override public String toString() {
|
@Override public String toString() {
|
||||||
return delegate + ".serializeNulls()";
|
return delegate + ".serializeNulls()";
|
||||||
}
|
}
|
||||||
@@ -136,6 +144,9 @@ public abstract class JsonAdapter<T> {
|
|||||||
delegate.toJson(writer, value);
|
delegate.toJson(writer, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Override boolean isLenient() {
|
||||||
|
return delegate.isLenient();
|
||||||
|
}
|
||||||
@Override public String toString() {
|
@Override public String toString() {
|
||||||
return delegate + ".nullSafe()";
|
return delegate + ".nullSafe()";
|
||||||
}
|
}
|
||||||
@@ -164,6 +175,9 @@ public abstract class JsonAdapter<T> {
|
|||||||
writer.setLenient(lenient);
|
writer.setLenient(lenient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Override boolean isLenient() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@Override public String toString() {
|
@Override public String toString() {
|
||||||
return delegate + ".lenient()";
|
return delegate + ".lenient()";
|
||||||
}
|
}
|
||||||
@@ -191,6 +205,9 @@ public abstract class JsonAdapter<T> {
|
|||||||
@Override public void toJson(JsonWriter writer, @Nullable T value) throws IOException {
|
@Override public void toJson(JsonWriter writer, @Nullable T value) throws IOException {
|
||||||
delegate.toJson(writer, value);
|
delegate.toJson(writer, value);
|
||||||
}
|
}
|
||||||
|
@Override boolean isLenient() {
|
||||||
|
return delegate.isLenient();
|
||||||
|
}
|
||||||
@Override public String toString() {
|
@Override public String toString() {
|
||||||
return delegate + ".failOnUnknown()";
|
return delegate + ".failOnUnknown()";
|
||||||
}
|
}
|
||||||
@@ -223,12 +240,19 @@ public abstract class JsonAdapter<T> {
|
|||||||
writer.setIndent(originalIndent);
|
writer.setIndent(originalIndent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Override boolean isLenient() {
|
||||||
|
return delegate.isLenient();
|
||||||
|
}
|
||||||
@Override public String toString() {
|
@Override public String toString() {
|
||||||
return delegate + ".indent(\"" + indent + "\")";
|
return delegate + ".indent(\"" + indent + "\")";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isLenient() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public interface Factory {
|
public interface Factory {
|
||||||
/**
|
/**
|
||||||
* Attempts to create an adapter for {@code type} annotated with {@code annotations}. This
|
* Attempts to create an adapter for {@code type} annotated with {@code annotations}. This
|
||||||
|
@@ -21,6 +21,7 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.Parameterized;
|
import org.junit.runners.Parameterized;
|
||||||
@@ -182,4 +183,67 @@ public final class JsonAdapterTest {
|
|||||||
serializeNulls.toJson(writer, Collections.<String, String>singletonMap("a", null));
|
serializeNulls.toJson(writer, Collections.<String, String>singletonMap("a", null));
|
||||||
assertThat(factory.json()).isEqualTo("{\"a\":null}");
|
assertThat(factory.json()).isEqualTo("{\"a\":null}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test public void stringDocumentMustBeFullyConsumed() throws IOException {
|
||||||
|
JsonAdapter<String> brokenAdapter = new JsonAdapter<String>() {
|
||||||
|
@Override public String fromJson(JsonReader reader) throws IOException {
|
||||||
|
return "Forgot to call reader.nextString().";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void toJson(JsonWriter writer, @Nullable String value) throws IOException {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
brokenAdapter.fromJson("\"value\"");
|
||||||
|
fail();
|
||||||
|
} catch (JsonDataException e) {
|
||||||
|
assertThat(e).hasMessage("JSON document was not fully consumed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void adapterFromJsonStringPeeksAtEnd() throws IOException {
|
||||||
|
JsonAdapter<Boolean> adapter = new JsonAdapter<Boolean>() {
|
||||||
|
@Override public Boolean fromJson(JsonReader reader) throws IOException {
|
||||||
|
return reader.nextBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void toJson(JsonWriter writer, @Nullable Boolean value) throws IOException {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
adapter.fromJson("true true");
|
||||||
|
fail();
|
||||||
|
} catch (JsonEncodingException e) {
|
||||||
|
assertThat(e).hasMessage(
|
||||||
|
"Use JsonReader.setLenient(true) to accept malformed JSON at path $");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void lenientAdapterFromJsonStringDoesNotPeekAtEnd() throws IOException {
|
||||||
|
JsonAdapter<Boolean> adapter = new JsonAdapter<Boolean>() {
|
||||||
|
@Override public Boolean fromJson(JsonReader reader) throws IOException {
|
||||||
|
return reader.nextBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void toJson(JsonWriter writer, @Nullable Boolean value) throws IOException {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}.lenient();
|
||||||
|
assertThat(adapter.fromJson("true true")).isEqualTo(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void adaptersDelegateLeniency() throws IOException {
|
||||||
|
JsonAdapter<Boolean> adapter = new JsonAdapter<Boolean>() {
|
||||||
|
@Override public Boolean fromJson(JsonReader reader) throws IOException {
|
||||||
|
return reader.nextBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void toJson(JsonWriter writer, @Nullable Boolean value) throws IOException {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}.lenient().nullSafe();
|
||||||
|
assertThat(adapter.fromJson("true true")).isEqualTo(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user