@@ -12,58 +12,61 @@ import java.lang.reflect.WildcardType
1212/* *
1313 * @author Andrew Potter
1414 */
15- internal class GenericType (private val mostSpecificType : JavaType , private val options : SchemaParserOptions ) {
15+ internal class GenericType (private val containingType : JavaType , private val options : SchemaParserOptions ) {
1616
17- fun isTypeAssignableFromRawClass (type : ParameterizedType , clazz : Class <* >) =
18- clazz.isAssignableFrom(getRawClass(type.rawType))
17+ fun getRawClass () = getRawClass(containingType)
1918
20- fun getRawClass () = getRawClass(mostSpecificType )
19+ fun getRawClass (type : JavaType ): Class < * > = TypeUtils .getRawType(type, containingType )
2120
22- fun getRawClass (type : JavaType ): Class <* > = TypeUtils .getRawType(type, mostSpecificType)
23-
24- fun isAssignableFrom (type : JavaType ) = TypeUtils .isAssignable(type, mostSpecificType)
21+ fun isAssignableFrom (type : JavaType ) = TypeUtils .isAssignable(type, containingType)
2522
2623 /* *
27- * Unwrap certain Java types to find the "real" class.
24+ * Turns a type as declared in the source (a method's return or parameter type, or a field's type) into the type
25+ * the GraphQL type is matched against:
26+ * - type variables are resolved relative to the containing type,
27+ * e.g. `T` of `AbstractItem<T>.getId()` becomes `Long` for `class Item : AbstractItem<Long>()`
28+ * - generic wrappers are replaced by their wrapped type, e.g. `CompletableFuture<Foo>` becomes `Foo`
29+ * - wildcards are replaced by their upper bound, e.g. `? extends Foo` becomes `Foo`
30+ * - primitives are replaced by their boxed class, e.g. `int` becomes `Integer`
2831 */
2932 fun unwrapGenericType (javaType : JavaType ): JavaType {
30- return when (val type = replaceTypeVariable (javaType)) {
33+ return when (val type = resolveTypeVariables (javaType)) {
3134 is ParameterizedType -> {
3235 val rawType = type.rawType
33- val genericType = options.genericWrappers.find { it.type == rawType }
36+ val wrapper = options.genericWrappers.find { it.type == rawType }
3437 ? : return type
3538
3639 val typeArguments = type.actualTypeArguments
37- if (typeArguments.size <= genericType .index) {
38- throw IndexOutOfBoundsException (" Generic type '${TypeUtils .toString(type)} ' does not have a type argument at index ${genericType .index} !" )
40+ if (typeArguments.size <= wrapper .index) {
41+ throw IndexOutOfBoundsException (" Generic type '${TypeUtils .toString(type)} ' does not have a type argument at index ${wrapper .index} !" )
3942 }
4043
41- val unwrapsTo = genericType .schemaWrapper.invoke(typeArguments[genericType .index])
44+ val unwrapsTo = wrapper .schemaWrapper.invoke(typeArguments[wrapper .index])
4245 unwrapGenericType(unwrapsTo)
4346 }
44- is TypeVariable <* > -> error(" Could not resolve type variable '${TypeUtils .toLongString(type)} ' relative to ${TypeUtils .toString(mostSpecificType )} " )
47+ is TypeVariable <* > -> error(" Could not resolve type variable '${TypeUtils .toLongString(type)} ' relative to ${TypeUtils .toString(containingType )} " )
4548 is WildcardType -> type.upperBounds.firstOrNull()
4649 ? : error(" Unable to unwrap type, wildcard has no upper bound: $type " )
4750 is Class <* > -> if (type.isPrimitive) Primitives .wrap(type) else type
4851 else -> error(" Unable to unwrap type: $type " )
4952 }
5053 }
5154
52- private fun replaceTypeVariable (type : JavaType , resolving : Set <TypeVariable <* >> = emptySet()): JavaType {
55+ private fun resolveTypeVariables (type : JavaType , resolving : Set <TypeVariable <* >> = emptySet()): JavaType {
5356 return when (type) {
5457 is ParameterizedType -> {
55- val actualTypeArguments = type.actualTypeArguments.map { replaceTypeVariable (it, resolving) }.toTypedArray()
56- ParameterizedTypeImpl (type.rawType as Class <* >, actualTypeArguments, type.ownerType?.let { replaceTypeVariable (it, resolving) })
58+ val actualTypeArguments = type.actualTypeArguments.map { resolveTypeVariables (it, resolving) }.toTypedArray()
59+ ParameterizedTypeImpl (type.rawType as Class <* >, actualTypeArguments, type.ownerType?.let { resolveTypeVariables (it, resolving) })
5760 }
5861 is WildcardType -> TypeUtils .wildcardType()
59- .withUpperBounds(* type.upperBounds.map { replaceTypeVariable (it, resolving) }.toTypedArray())
60- .withLowerBounds(* type.lowerBounds.map { replaceTypeVariable (it, resolving) }.toTypedArray())
62+ .withUpperBounds(* type.upperBounds.map { resolveTypeVariables (it, resolving) }.toTypedArray())
63+ .withLowerBounds(* type.lowerBounds.map { resolveTypeVariables (it, resolving) }.toTypedArray())
6164 .build()
6265 is ResolvedType -> {
6366 if (type.typeParameters.isEmpty()) {
6467 type.erasedType
6568 } else {
66- val actualTypeArguments = type.typeParameters.map { replaceTypeVariable (it) }.toTypedArray()
69+ val actualTypeArguments = type.typeParameters.map { resolveTypeVariables (it) }.toTypedArray()
6770 ParameterizedTypeImpl (type.erasedType, actualTypeArguments, null )
6871 }
6972 }
@@ -73,19 +76,17 @@ internal class GenericType(private val mostSpecificType: JavaType, private val o
7376 // only a variable leaked from a raw type can be bound to a type containing itself (e.g. T -> List<T>),
7477 // erase it like the raw type does instead of expanding it forever
7578 type in resolving -> TypeUtils .getRawType(type.bounds.first(), null ) ? : Any ::class .java
76- // the most specific type binds the variables of all its supertypes
77- genericDeclaration is Class <* > -> generateSequence(mostSpecificType ) { (it as ? ParameterizedType )?.ownerType }
79+ // the containing type binds the variables of all its supertypes
80+ genericDeclaration is Class <* > -> generateSequence(containingType ) { (it as ? ParameterizedType )?.ownerType }
7881 // an inner class can also use the variables of its outer class, those are bound by its owner type (e.g. Connection<Owner>.Entry)
7982 .firstNotNullOfOrNull { TypeUtils .getTypeArguments(it, genericDeclaration)?.get(type) }
8083 // keep the full type argument (e.g. List<Foo>) rather than its raw class so nested generics aren't lost
81- ?.let { replaceTypeVariable (it, resolving + type) }
84+ ?.let { resolveTypeVariables (it, resolving + type) }
8285 ? : type
8386 else -> type
8487 }
8588 }
86- else -> {
87- type
88- }
89+ else -> type
8990 }
9091 }
9192}
0 commit comments