diff --git a/moshi/src/main/java/com/squareup/moshi/Types.kt b/moshi/src/main/java/com/squareup/moshi/Types.kt index af7a10a..387de8f 100644 --- a/moshi/src/main/java/com/squareup/moshi/Types.kt +++ b/moshi/src/main/java/com/squareup/moshi/Types.kt @@ -215,11 +215,18 @@ public object Types { is Class<*> -> { return if (b is GenericArrayType) { equals(a.componentType, b.genericComponentType) + } else if (b is ParameterizedType && a.rawType == b.rawType) { + // Class instance with generic info, from method return types + return a.typeParameters.flatMap { it.bounds.toList() } == b.actualTypeArguments.toList() } else { a == b // Class already specifies equals(). } } is ParameterizedType -> { + // Class instance with generic info, from method return types + if (b is Class<*> && a.rawType == b.rawType) { + return b.typeParameters.map { it.bounds }.toTypedArray().flatten() == a.actualTypeArguments.toList() + } if (b !is ParameterizedType) return false val aTypeArguments = if (a is ParameterizedTypeImpl) a.typeArguments else a.actualTypeArguments val bTypeArguments = if (b is ParameterizedTypeImpl) b.typeArguments else b.actualTypeArguments diff --git a/moshi/src/test/java/com/squareup/moshi/TypesTest.java b/moshi/src/test/java/com/squareup/moshi/TypesTest.java index 6243eae..bca3473 100644 --- a/moshi/src/test/java/com/squareup/moshi/TypesTest.java +++ b/moshi/src/test/java/com/squareup/moshi/TypesTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.fail; import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.Target; +import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; @@ -33,6 +34,7 @@ import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; +import kotlin.NotImplementedError; import org.junit.Test; public final class TypesTest { @@ -204,6 +206,8 @@ public final class TypesTest { private static final class D {} + private static final class E {} + /** * Given a parameterized type {@code A}, returns B. If the specified type is not a generic * type, returns null. @@ -292,6 +296,25 @@ public final class TypesTest { assertThat(Types.equals(Types.arrayOf(String.class), String[].class)).isTrue(); } + private E methodReturningE() { + throw new NotImplementedError(); // Intentionally not implemented + } + + @Test + public void parameterizedTypeMatchesClassWithGenericInfoFromReturn() { + Type type = Types.newParameterizedTypeWithOwner(TypesTest.class, E.class, A.class, B.class); + Method returningE = null; + for (Method method : TypesTest.class.getDeclaredMethods()) { + if (method.getName().contains("methodReturningE")) { + returningE = method; + break; + } + } + Type rawType = Types.getRawType(returningE.getGenericReturnType()); + assertThat(Types.equals(type, rawType)).isTrue(); + assertThat(Types.equals(rawType, type)).isTrue(); + } + @Test public void parameterizedAndWildcardTypesCannotHavePrimitiveArguments() throws Exception { try {