@@ -3,7 +3,6 @@ package graphql.kickstart.tools
33import graphql.kickstart.tools.ScanDictionary.DictionaryReference
44import graphql.kickstart.tools.ScanDictionary.FieldTypeReference
55import graphql.kickstart.tools.ScanDictionary.InitialDictionaryEntry
6- import graphql.kickstart.tools.ScanDictionary.SealedSubclassReference
76import graphql.kickstart.tools.ScanDictionary.UnionMemberReference
87import graphql.kickstart.tools.ScanDictionary.UnusedTypeReference
98import graphql.kickstart.tools.resolver.FieldResolver
@@ -15,12 +14,10 @@ import graphql.language.*
1514import graphql.schema.idl.ScalarInfo
1615import graphql.schema.idl.TypeUtil
1716import org.apache.commons.lang3.ClassUtils
18- import org.apache.commons.lang3.reflect.TypeUtils
1917import org.slf4j.LoggerFactory
2018import java.lang.reflect.Field
2119import java.lang.reflect.Member
2220import java.lang.reflect.Modifier
23- import java.lang.reflect.ParameterizedType
2421
2522/* *
2623 * @author Andrew Potter
@@ -66,6 +63,7 @@ internal class SchemaClassScanner(
6663 private val unvalidatedTypes = mutableSetOf<TypeDefinition <* >>()
6764 private val queue = linkedSetOf<QueueItem >()
6865 private val dictionary = ScanDictionary (options, log, typeExtensions, definitionsByName, typeClassMatcher, this .initialDictionary, ::enqueue, ::handleFoundScalarType)
66+ private val sealedSubclassMatcher = SealedSubclassMatcher (dictionary, typeExtensions)
6967
7068 private val fieldResolversByType = mutableMapOf<ObjectTypeDefinition , MutableMap <FieldDefinition , FieldResolver >>()
7169
@@ -399,70 +397,14 @@ internal class SchemaClassScanner(
399397 }
400398 }
401399
402- val sealedMatches = typesWithoutClass.filterIsInstance<ObjectTypeDefinition >().mapNotNull { sealedSubclassMatches(it).singleOrNull() }
400+ val sealedMatches = typesWithoutClass.filterIsInstance<ObjectTypeDefinition >().mapNotNull { sealedSubclassMatcher. sealedSubclassMatches(it).singleOrNull() }
403401 if (sealedMatches.isEmpty()) {
404- typesWithoutClass.firstOrNull()?.let { throw SchemaClassScannerError (failureMessage(it) + sealedSubclassHint(it)) }
402+ typesWithoutClass.firstOrNull()?.let { throw SchemaClassScannerError (failureMessage(it) + sealedSubclassMatcher. sealedSubclassHint(it)) }
405403 }
406404
407405 sealedMatches.forEach { dictionary.handleFoundType(it) }
408406 }
409407
410- private fun sealedSubclassHint (type : TypeDefinition <* >): String {
411- if (type !is ObjectTypeDefinition ) {
412- return " "
413- }
414-
415- val sealedTypes = sealedTypesOf(type)
416- if (sealedTypes.isEmpty()) {
417- return " "
418- }
419-
420- val sealedTypeNames = sealedTypes.joinToString(" or " ) { it.unwrap().name }
421- val matches = sealedSubclassMatches(type)
422- return if (matches.isEmpty()) {
423- " No subclass of sealed type $sealedTypeNames is named '${type.name} '."
424- } else {
425- " More than one subclass of sealed type $sealedTypeNames is named '${type.name} ': ${matches.joinToString { it.javaType.unwrap().name }} ."
426- }
427- }
428-
429- private fun sealedSubclassMatches (type : ObjectTypeDefinition ): List <TypeClassMatcher .ValidMatch > =
430- sealedTypesOf(type)
431- .flatMap { sealedType ->
432- sealedSubclasses(sealedType.unwrap())
433- .filter { it.simpleName == type.name }
434- .map { TypeClassMatcher .ValidMatch (type, withSealedTypeArguments(it, sealedType), SealedSubclassReference (sealedType)) }
435- }
436- .distinctBy { it.javaType.unwrap() }
437-
438- private fun sealedTypesOf (type : ObjectTypeDefinition ): List <JavaType > =
439- dictionary
440- .filterKeys { definition ->
441- when (definition) {
442- is UnionTypeDefinition -> definition.withExtensions(typeExtensions).flatMap { it.memberTypes }.filterIsInstance<TypeName >().any { it.name == type.name }
443- is InterfaceTypeDefinition -> type.withExtensions(typeExtensions).flatMap { it.implements }.filterIsInstance<TypeName >().any { it.name == definition.name }
444- else -> false
445- }
446- }
447- .values.mapNotNull { it.javaType }
448- .distinct()
449- .filter { it.unwrap().kotlin.isSealed }
450-
451- // kotlin-reflect also returns the permitted subclasses of Java sealed classes
452- private fun sealedSubclasses (clazz : Class <* >): List <Class <* >> =
453- clazz.kotlin.sealedSubclasses.flatMap { listOf (it.java) + sealedSubclasses(it.java) }
454-
455- private fun withSealedTypeArguments (subclass : Class <* >, sealedType : JavaType ): JavaType {
456- if (sealedType !is ParameterizedType || subclass.typeParameters.isEmpty()) {
457- return subclass
458- }
459-
460- return TypeUtils .determineTypeArguments(subclass, sealedType)
461- ?.takeIf { it.keys.containsAll(subclass.typeParameters.asList()) }
462- ?.let { TypeUtils .parameterize(subclass, it) }
463- ? : subclass
464- }
465-
466408 /* *
467409 * Scan a new object for types that haven't been mapped yet.
468410 */
0 commit comments