From dc450e6192950da77c05279f50b396f5fd30ece8 Mon Sep 17 00:00:00 2001 From: Eric Cochran Date: Tue, 3 Apr 2018 17:37:38 -0700 Subject: [PATCH] Resolve generic property types in KotlinJsonAdapter. --- .../moshi/kotlin/KotlinJsonAdapter.kt | 3 +- .../moshi/kotlin/KotlinJsonAdapterTest.kt | 49 ++++++++++++++++++- .../main/java/com/squareup/moshi/Types.java | 3 +- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/kotlin/src/main/java/com/squareup/moshi/kotlin/KotlinJsonAdapter.kt b/kotlin/src/main/java/com/squareup/moshi/kotlin/KotlinJsonAdapter.kt index 3d3b205..3f005c9 100644 --- a/kotlin/src/main/java/com/squareup/moshi/kotlin/KotlinJsonAdapter.kt +++ b/kotlin/src/main/java/com/squareup/moshi/kotlin/KotlinJsonAdapter.kt @@ -225,8 +225,9 @@ class KotlinJsonAdapterFactory : JsonAdapter.Factory { } val name = jsonAnnotation?.name ?: property.name + val resolvedPropertyType = Types.resolve(type, rawType, property.returnType.javaType) val adapter = moshi.adapter( - property.returnType.javaType, Util.jsonAnnotations(allAnnotations.toTypedArray())) + resolvedPropertyType, Util.jsonAnnotations(allAnnotations.toTypedArray())) bindingsByName[property.name] = KotlinJsonAdapter.Binding(name, adapter, property as KProperty1, parameter) diff --git a/kotlin/src/test/java/com/squareup/moshi/kotlin/KotlinJsonAdapterTest.kt b/kotlin/src/test/java/com/squareup/moshi/kotlin/KotlinJsonAdapterTest.kt index 6fc35d2..706cf30 100644 --- a/kotlin/src/test/java/com/squareup/moshi/kotlin/KotlinJsonAdapterTest.kt +++ b/kotlin/src/test/java/com/squareup/moshi/kotlin/KotlinJsonAdapterTest.kt @@ -21,6 +21,7 @@ import com.squareup.moshi.JsonDataException import com.squareup.moshi.JsonQualifier import com.squareup.moshi.Moshi import com.squareup.moshi.ToJson +import com.squareup.moshi.Types import org.assertj.core.api.Assertions.assertThat import org.junit.Assert.fail import org.junit.Test @@ -763,7 +764,53 @@ class KotlinJsonAdapterTest { var v26: Int, var v27: Int, var v28: Int, var v29: Int, var v30: Int, var v31: Int, var v32: Int, var v33: Int) - // TODO(jwilson): resolve generic types? + data class Box(val data: T) + + @Test fun genericTypes() { + val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build() + val stringBoxAdapter = moshi.adapter>( + Types.newParameterizedTypeWithOwner(KotlinJsonAdapterTest::class.java, Box::class.java, + String::class.java)) + assertThat(stringBoxAdapter.fromJson("""{"data":"hello"}""")).isEqualTo(Box("hello")) + assertThat(stringBoxAdapter.toJson(Box("hello"))).isEqualTo("""{"data":"hello"}""") + } + + data class NestedGenerics(val value: Map>>) + + @Test fun nestedGenericTypes() { + val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build() + val type = Types.newParameterizedTypeWithOwner( + KotlinJsonAdapterTest::class.java, + NestedGenerics::class.java, + String::class.java, + Int::class.javaObjectType, + Types.newParameterizedTypeWithOwner( + KotlinJsonAdapterTest::class.java, + Box::class.java, + String::class.java + ) + ) + val adapter = moshi.adapter>>(type).indent(" ") + val json = """ + |{ + | "value": { + | "hello": { + | "1": [ + | { + | "data": " " + | }, + | { + | "data": "world!" + | } + | ] + | } + | } + |} + """.trimMargin() + val value = NestedGenerics(mapOf("hello" to mapOf(1 to listOf(Box(" "), Box("world!"))))) + assertThat(adapter.fromJson(json)).isEqualTo(value) + assertThat(adapter.toJson(value)).isEqualTo(json) + } @Retention(RUNTIME) @JsonQualifier diff --git a/moshi/src/main/java/com/squareup/moshi/Types.java b/moshi/src/main/java/com/squareup/moshi/Types.java index 80459d1..ae6fdf0 100644 --- a/moshi/src/main/java/com/squareup/moshi/Types.java +++ b/moshi/src/main/java/com/squareup/moshi/Types.java @@ -373,7 +373,8 @@ public final class Types { return new Type[] { Object.class, Object.class }; } - static Type resolve(Type context, Class contextRawType, Type toResolve) { + @CheckReturnValue // TODO(eric): Move this to internal Utils. + public static Type resolve(Type context, Class contextRawType, Type toResolve) { // This implementation is made a little more complicated in an attempt to avoid object-creation. while (true) { if (toResolve instanceof TypeVariable) {