diff --git a/kotlin-codegen/compiler/src/main/java/com/squareup/moshi/JsonClassCodeGenProcessor.kt b/kotlin-codegen/compiler/src/main/java/com/squareup/moshi/JsonClassCodeGenProcessor.kt index 3c32715..6b4ebbd 100644 --- a/kotlin-codegen/compiler/src/main/java/com/squareup/moshi/JsonClassCodeGenProcessor.kt +++ b/kotlin-codegen/compiler/src/main/java/com/squareup/moshi/JsonClassCodeGenProcessor.kt @@ -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") } diff --git a/moshi/src/main/java/com/squareup/moshi/JsonAdapter.java b/moshi/src/main/java/com/squareup/moshi/JsonAdapter.java index 14927a5..345c027 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonAdapter.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonAdapter.java @@ -153,6 +153,39 @@ public abstract class JsonAdapter { }; } + /** + * 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}. + * + *

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 nonNull() { + final JsonAdapter delegate = this; + return new JsonAdapter() { + @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 lenient() { final JsonAdapter delegate = this; diff --git a/moshi/src/test/java/com/squareup/moshi/JsonAdapterTest.java b/moshi/src/test/java/com/squareup/moshi/JsonAdapterTest.java index 7cbf785..34968a7 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonAdapterTest.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonAdapterTest.java @@ -95,6 +95,45 @@ public final class JsonAdapterTest { assertThat(factory.json()).isEqualTo("[\"A\",null,\"C\"]"); } + @Test public void nonNull() throws Exception { + JsonAdapter toUpperCase = new JsonAdapter() { + @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 alwaysSkip = new JsonAdapter() { @Override public String fromJson(JsonReader reader) throws IOException {