diff --git a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/TypeRenderer.kt b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/TypeRenderer.kt index e1259eb..d6957fc 100644 --- a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/TypeRenderer.kt +++ b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/TypeRenderer.kt @@ -43,6 +43,16 @@ abstract class TypeRenderer { fun render(typeName: TypeName): CodeBlock { if (typeName.nullable) { + if (typeName == BOOLEAN.asNullable() + || typeName == BYTE.asNullable() + || typeName == CHAR.asNullable() + || typeName == DOUBLE.asNullable() + || typeName == FLOAT.asNullable() + || typeName == INT.asNullable() + || typeName == LONG.asNullable() + || typeName == SHORT.asNullable()) { + return CodeBlock.of("%T::class.javaObjectType", typeName.asNonNullable()) + } return render(typeName.asNonNullable()) } diff --git a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codgen/GeneratedAdaptersTest.kt b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codgen/GeneratedAdaptersTest.kt index 1305d41..c5eca06 100644 --- a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codgen/GeneratedAdaptersTest.kt +++ b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codgen/GeneratedAdaptersTest.kt @@ -17,9 +17,12 @@ package com.squareup.moshi.kotlin.codgen import com.squareup.moshi.FromJson import com.squareup.moshi.Json +import com.squareup.moshi.JsonAdapter import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonDataException import com.squareup.moshi.JsonQualifier +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter import com.squareup.moshi.Moshi import com.squareup.moshi.ToJson import com.squareup.moshi.Types @@ -28,6 +31,7 @@ import org.intellij.lang.annotations.Language import org.junit.Assert.fail import org.junit.Ignore import org.junit.Test +import java.lang.reflect.Type import java.util.Locale class GeneratedAdaptersTest { @@ -865,6 +869,36 @@ class GeneratedAdaptersTest { return s.toLowerCase(Locale.US) } } + + @JsonClass(generateAdapter = true) + data class HasNullableBoolean(val boolean: Boolean?) + + @Test fun nullablePrimitivesUseBoxedPrimitiveAdapters() { + val moshi = Moshi.Builder() + .add(JsonAdapter.Factory { type, annotations, moshi -> + if (Boolean::class.javaObjectType == type) { + return@Factory object:JsonAdapter() { + override fun fromJson(reader: JsonReader): Boolean? { + if (reader.peek() != JsonReader.Token.BOOLEAN) { + reader.skipValue() + return null + } + return reader.nextBoolean() + } + + override fun toJson(writer: JsonWriter, value: Boolean?) { + writer.value(value) + } + } + } + null + }) + .build() + val adapter = moshi.adapter(HasNullableBoolean::class.java).serializeNulls() + assertThat(adapter.fromJson("""{"boolean":"not a boolean"}""")) + .isEqualTo(HasNullableBoolean(null)) + assertThat(adapter.toJson(HasNullableBoolean(null))).isEqualTo("""{"boolean":null}""") + } } // Has to be outside to avoid Types seeing an owning class diff --git a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapterTest.kt b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapterTest.kt index 87499f6..d1a7df3 100644 --- a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapterTest.kt +++ b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapterTest.kt @@ -17,9 +17,12 @@ package com.squareup.moshi.kotlin.reflect import com.squareup.moshi.FromJson import com.squareup.moshi.Json +import com.squareup.moshi.JsonAdapter import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonDataException import com.squareup.moshi.JsonQualifier +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter import com.squareup.moshi.Moshi import com.squareup.moshi.ToJson import com.squareup.moshi.Types @@ -881,4 +884,33 @@ class KotlinJsonAdapterTest { return s.toLowerCase(Locale.US) } } + + data class HasNullableBoolean(val boolean: Boolean?) + + @Test fun nullablePrimitivesUseBoxedPrimitiveAdapters() { + val moshi = Moshi.Builder() + .add(JsonAdapter.Factory { type, annotations, moshi -> + if (Boolean::class.javaObjectType == type) { + return@Factory object: JsonAdapter() { + override fun fromJson(reader: JsonReader): Boolean? { + if (reader.peek() != JsonReader.Token.BOOLEAN) { + reader.skipValue() + return null + } + return reader.nextBoolean() + } + + override fun toJson(writer: JsonWriter, value: Boolean?) { + writer.value(value) + } + } + } + null + }) + .build() + val adapter = moshi.adapter(HasNullableBoolean::class.java).serializeNulls() + assertThat(adapter.fromJson("""{"boolean":"not a boolean"}""")) + .isEqualTo(HasNullableBoolean(null)) + assertThat(adapter.toJson(HasNullableBoolean(null))).isEqualTo("""{"boolean":null}""") + } }