Merge pull request #482 from square/jwilson.0404.nonNull
JsonAdapter.nonNull() forbids explicit nulls in the JSON body
This commit is contained in:
commit
7cab83a8f2
3 changed files with 73 additions and 1 deletions
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue