Merge pull request #482 from square/jwilson.0404.nonNull

JsonAdapter.nonNull() forbids explicit nulls in the JSON body
This commit is contained in:
Jesse Wilson 2018-04-05 06:42:19 -07:00 committed by GitHub
commit 7cab83a8f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 1 deletions

View file

@ -196,7 +196,7 @@ class JsonClassCodeGenProcessor : KotlinAbstractProcessor(), KotlinMetadataUtils
val hasDefault = parameter?.declaresDefaultValue ?: true
if (enclosedElement.modifiers.contains(Modifier.TRANSIENT)) {
if (Modifier.TRANSIENT in enclosedElement.modifiers) {
if (!hasDefault) {
throw IllegalArgumentException("No default value for transient property $name")
}

View file

@ -153,6 +153,39 @@ public abstract class JsonAdapter<T> {
};
}
/**
* Returns a JSON adapter equal to this JSON adapter, but that refuses null values. If null is
* read or written this will throw a {@link JsonDataException}.
*
* <p>Note that this adapter will not usually be invoked for absent values and so those must be
* handled elsewhere. This should only be used to fail on explicit nulls.
*/
@CheckReturnValue public final JsonAdapter<T> nonNull() {
final JsonAdapter<T> delegate = this;
return new JsonAdapter<T>() {
@Override public @Nullable T fromJson(JsonReader reader) throws IOException {
if (reader.peek() == JsonReader.Token.NULL) {
throw new JsonDataException("Unexpected null at " + reader.getPath());
} else {
return delegate.fromJson(reader);
}
}
@Override public void toJson(JsonWriter writer, @Nullable T value) throws IOException {
if (value == null) {
throw new JsonDataException("Unexpected null at " + writer.getPath());
} else {
delegate.toJson(writer, value);
}
}
@Override boolean isLenient() {
return delegate.isLenient();
}
@Override public String toString() {
return delegate + ".nonNull()";
}
};
}
/** Returns a JSON adapter equal to this, but is lenient when reading and writing. */
@CheckReturnValue public final JsonAdapter<T> lenient() {
final JsonAdapter<T> delegate = this;

View file

@ -95,6 +95,45 @@ public final class JsonAdapterTest {
assertThat(factory.json()).isEqualTo("[\"A\",null,\"C\"]");
}
@Test public void nonNull() throws Exception {
JsonAdapter<String> toUpperCase = new JsonAdapter<String>() {
@Override public String fromJson(JsonReader reader) throws IOException {
return reader.nextString().toUpperCase(Locale.US);
}
@Override public void toJson(JsonWriter writer, String value) throws IOException {
writer.value(value.toUpperCase(Locale.US));
}
}.nonNull();
JsonReader reader = factory.newReader("[\"a\", null, \"c\"]");
reader.beginArray();
assertThat(toUpperCase.fromJson(reader)).isEqualTo("A");
try {
toUpperCase.fromJson(reader);
fail();
} catch (JsonDataException expected) {
assertThat(expected).hasMessage("Unexpected null at $[1]");
assertThat(reader.nextNull()).isNull();
}
assertThat(toUpperCase.fromJson(reader)).isEqualTo("C");
reader.endArray();
JsonWriter writer = factory.newWriter();
writer.beginArray();
toUpperCase.toJson(writer, "a");
try {
toUpperCase.toJson(writer, null);
fail();
} catch (JsonDataException expected) {
assertThat(expected).hasMessage("Unexpected null at $[1]");
writer.nullValue();
}
toUpperCase.toJson(writer, "c");
writer.endArray();
assertThat(factory.json()).isEqualTo("[\"A\",null,\"C\"]");
}
@Test public void failOnUnknown() throws Exception {
JsonAdapter<String> alwaysSkip = new JsonAdapter<String>() {
@Override public String fromJson(JsonReader reader) throws IOException {