diff --git a/src/main/kotlin/graphql/kickstart/tools/GenericType.kt b/src/main/kotlin/graphql/kickstart/tools/GenericType.kt index 6b76b3d0..35b9df7c 100644 --- a/src/main/kotlin/graphql/kickstart/tools/GenericType.kt +++ b/src/main/kotlin/graphql/kickstart/tools/GenericType.kt @@ -141,14 +141,14 @@ internal open class GenericType(protected val mostSpecificType: JavaType, protec return when (type) { is ParameterizedType -> { val actualTypeArguments = type.actualTypeArguments.map { replaceTypeVariable(it) }.toTypedArray() - ParameterizedTypeImpl.make(type.rawType as Class<*>?, actualTypeArguments, type.ownerType) + ParameterizedTypeImpl(type.rawType as Class<*>, actualTypeArguments, type.ownerType) } is ResolvedType -> { if (type.typeParameters.isEmpty()) { type.erasedType } else { val actualTypeArguments = type.typeParameters.map { replaceTypeVariable(it) }.toTypedArray() - ParameterizedTypeImpl.make(type.erasedType, actualTypeArguments, null) + ParameterizedTypeImpl(type.erasedType, actualTypeArguments, null) } } is TypeVariable<*> -> { diff --git a/src/main/kotlin/graphql/kickstart/tools/SchemaParserOptions.kt b/src/main/kotlin/graphql/kickstart/tools/SchemaParserOptions.kt index c161504f..4141cdef 100644 --- a/src/main/kotlin/graphql/kickstart/tools/SchemaParserOptions.kt +++ b/src/main/kotlin/graphql/kickstart/tools/SchemaParserOptions.kt @@ -250,12 +250,9 @@ data class SchemaParserOptions internal constructor( index: Int, transformer: (T) -> Any? ): GenericWrapper where T : Any { - return withTransformer( - type, - index, - transformer, - { innerType -> ParameterizedTypeImpl.make(List::class.java, arrayOf(innerType), null) } - ) + return withTransformer(type, index, transformer) { innerType -> + ParameterizedTypeImpl(List::class.java, arrayOf(innerType), null) + } } fun listCollectionWithTransformer( diff --git a/src/main/kotlin/graphql/kickstart/tools/util/ParameterizedTypeImpl.java b/src/main/kotlin/graphql/kickstart/tools/util/ParameterizedTypeImpl.java deleted file mode 100644 index ab18cc59..00000000 --- a/src/main/kotlin/graphql/kickstart/tools/util/ParameterizedTypeImpl.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -package graphql.kickstart.tools.util; - -import java.lang.reflect.MalformedParameterizedTypeException; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.util.Arrays; -import java.util.Objects; -import java.util.StringJoiner; - -/** - * Implementing class for ParameterizedType interface. - */ -public class ParameterizedTypeImpl implements ParameterizedType { - - private final Type[] actualTypeArguments; - private final Class rawType; - private final Type ownerType; - - private ParameterizedTypeImpl( - Class rawType, Type[] actualTypeArguments, Type ownerType - ) { - this.actualTypeArguments = actualTypeArguments; - this.rawType = rawType; - this.ownerType = (ownerType != null) ? ownerType : rawType.getDeclaringClass(); - validateConstructorArguments(); - } - - private void validateConstructorArguments() { - TypeVariable[] formals = rawType.getTypeParameters(); - // check correct arity of actual type args - if (formals.length != actualTypeArguments.length) { - throw new MalformedParameterizedTypeException(); - } - for (int i = 0; i < actualTypeArguments.length; i++) { - // TODO check actual against formal bounds - } - } - - /** - * Static factory. Given a (generic) class, actual type arguments and an owner type, creates a parameterized type. This - * class can be instantiated with a raw type that does not represent a generic type, provided the list of actual type - * arguments is empty. If the ownerType argument is null, the declaring class of the raw type is used as the owner type. - *

This method throws a MalformedParameterizedTypeException - * under the following circumstances: If the number of actual type arguments (i.e., the size of the array {@code - * typeArgs}) does not correspond to the number of formal type arguments. If any of the actual type arguments is not an - * instance of the bounds on the corresponding formal. - * - * @param rawType the Class representing the generic type declaration being instantiated - * @param actualTypeArguments a (possibly empty) array of types representing the actual type arguments to the - * parameterized type - * @param ownerType the enclosing type, if known. - * @return An instance of {@code ParameterizedType} - * @throws MalformedParameterizedTypeException if the instantiation is invalid - */ - public static ParameterizedTypeImpl make(Class rawType, Type[] actualTypeArguments, Type ownerType) { - return new ParameterizedTypeImpl(rawType, actualTypeArguments, ownerType); - } - - /** - * Returns an array of {@code Type} objects representing the actual type arguments to this type. - *

Note that in some cases, the returned array be empty. This can occur - * if this type represents a non-parameterized type nested within a parameterized type. - * - * @return an array of {@code Type} objects representing the actual type arguments to this type - * @throws TypeNotPresentException if any of the actual type arguments refers to a non-existent type - * declaration - * @throws MalformedParameterizedTypeException if any of the actual type parameters refer to a parameterized type that - * cannot be instantiated for any reason - * @since 1.5 - */ - public Type[] getActualTypeArguments() { - return actualTypeArguments.clone(); - } - - /** - * Returns the {@code Type} object representing the class or interface that declared this type. - * - * @return the {@code Type} object representing the class or interface that declared this type - */ - public Class getRawType() { - return rawType; - } - - /** - * Returns a {@code Type} object representing the type that this type is a member of. For example, if this type is - * {@code O.I}, return a representation of {@code O}. - *

If this type is a top-level type, {@code null} is returned. - * - * @return a {@code Type} object representing the type that this type is a member of. If this type is a top-level type, - * {@code null} is returned - * @throws TypeNotPresentException if the owner type refers to a non-existent type declaration - * @throws MalformedParameterizedTypeException if the owner type refers to a parameterized type that cannot be - * instantiated for any reason - */ - public Type getOwnerType() { - return ownerType; - } - - /* - * From the JavaDoc for java.lang.reflect.ParameterizedType - * "Instances of classes that implement this interface must - * implement an equals() method that equates any two instances - * that share the same generic type declaration and have equal - * type parameters." - */ - @Override - public boolean equals(Object o) { - if (o instanceof ParameterizedType) { - // Check that information is equivalent - ParameterizedType that = (ParameterizedType) o; - - if (this == that) { - return true; - } - - Type thatOwner = that.getOwnerType(); - Type thatRawType = that.getRawType(); - - if (false) { // Debugging - boolean ownerEquality = (ownerType == null ? thatOwner == null : ownerType.equals(thatOwner)); - boolean rawEquality = (rawType == null ? thatRawType == null : rawType.equals(thatRawType)); - - boolean typeArgEquality = Arrays.equals(actualTypeArguments, // avoid clone - that.getActualTypeArguments()); - for (Type t : actualTypeArguments) { - System.out.printf("\t\t%s%s%n", t, t.getClass()); - } - - System.out.printf("\towner %s\traw %s\ttypeArg %s%n", ownerEquality, rawEquality, typeArgEquality); - return ownerEquality && rawEquality && typeArgEquality; - } - - return Objects.equals(ownerType, thatOwner) && Objects.equals(rawType, thatRawType) && Arrays.equals(actualTypeArguments, // avoid clone - that.getActualTypeArguments()); - } else { - return false; - } - } - - @Override - public int hashCode() { - return Arrays.hashCode(actualTypeArguments) ^ Objects.hashCode(ownerType) ^ Objects.hashCode(rawType); - } - - public String toString() { - StringBuilder sb = new StringBuilder(); - - if (ownerType != null) { - sb.append(ownerType.getTypeName()); - - sb.append("$"); - - if (ownerType instanceof ParameterizedTypeImpl) { - // Find simple name of nested type by removing the - // shared prefix with owner. - sb.append(rawType.getName().replace(((ParameterizedTypeImpl) ownerType).rawType.getName() + "$", "")); - } else { - sb.append(rawType.getSimpleName()); - } - } else { - sb.append(rawType.getName()); - } - - if (actualTypeArguments != null) { - StringJoiner sj = new StringJoiner(", ", "<", ">"); - sj.setEmptyValue(""); - for (Type t : actualTypeArguments) { - sj.add(t.getTypeName()); - } - sb.append(sj.toString()); - } - - return sb.toString(); - } -} diff --git a/src/main/kotlin/graphql/kickstart/tools/util/ParameterizedTypeImpl.kt b/src/main/kotlin/graphql/kickstart/tools/util/ParameterizedTypeImpl.kt new file mode 100644 index 00000000..abff7ead --- /dev/null +++ b/src/main/kotlin/graphql/kickstart/tools/util/ParameterizedTypeImpl.kt @@ -0,0 +1,49 @@ +package graphql.kickstart.tools.util + +import java.lang.reflect.ParameterizedType +import java.lang.reflect.Type + +class ParameterizedTypeImpl( + private val rawType: Class<*>, + private val actualTypeArguments: Array, + private val ownerType: Type? +) : ParameterizedType { + override fun getActualTypeArguments(): Array = actualTypeArguments.clone() + + override fun getRawType(): Type = rawType + + override fun getOwnerType(): Type? = ownerType + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ParameterizedTypeImpl + + if (rawType != other.rawType) return false + if (ownerType != other.ownerType) return false + if (!actualTypeArguments.contentEquals(other.actualTypeArguments)) return false + + return true + } + + override fun hashCode(): Int { + var result = rawType.hashCode() + result = 31 * result + (ownerType?.hashCode() ?: 0) + result = 31 * result + actualTypeArguments.contentHashCode() + return result + } + + override fun toString(): String = buildString { + if (ownerType != null) { + append(ownerType.typeName) + append("$") + append(rawType.simpleName) + } else { + append(rawType.name) + } + if (actualTypeArguments.isNotEmpty()) { + actualTypeArguments.joinTo(this, ",", "<", ">", transform = Type::getTypeName) + } + } +}