graphql.kickstart.tools.ResolverInfo.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of graphql-java-tools Show documentation
Show all versions of graphql-java-tools Show documentation
Tools to help map a GraphQL schema to existing Java objects.
package graphql.kickstart.tools
import graphql.kickstart.tools.resolver.FieldResolverScanner
import graphql.kickstart.tools.util.GraphQLRootResolver
import graphql.kickstart.tools.util.JavaType
import org.apache.commons.lang3.reflect.TypeUtils
internal abstract class ResolverInfo {
abstract fun getFieldSearches(): List
fun getRealResolverClass(resolver: GraphQLResolver<*>, options: SchemaParserOptions) =
options.proxyHandlers.find { it.canHandle(resolver) }
?.getTargetClass(resolver)
?: resolver.javaClass
}
internal interface DataClassTypeResolverInfo {
val dataClassType: Class
}
internal class NormalResolverInfo(
val resolver: GraphQLResolver<*>,
options: SchemaParserOptions
) : DataClassTypeResolverInfo, ResolverInfo() {
val resolverType = getRealResolverClass(resolver, options)
override val dataClassType = findDataClass()
private fun findDataClass(): Class {
val type = TypeUtils.getTypeArguments(resolverType, GraphQLResolver::class.java)[GraphQLResolver::class.java.typeParameters[0]]
if (type == null || type !is Class<*>) {
throw ResolverError("Unable to determine data class for resolver '${resolverType.name}' from generic interface! This is most likely a bug with graphql-java-tools.")
}
if (type == Void::class.java) {
throw ResolverError("Resolvers may not have ${Void::class.java.name} as their type, use a real type or use a root resolver interface.")
}
return type
}
override fun getFieldSearches(): List {
return listOf(
FieldResolverScanner.Search(resolverType, this, resolver, dataClassType),
FieldResolverScanner.Search(dataClassType, this, null)
)
}
}
internal class MultiResolverInfo(val resolverInfoList: List) : DataClassTypeResolverInfo, ResolverInfo() {
override val dataClassType = findDataClass()
/**
* Checks if all `ResolverInfo` instances are related to the same data type
*/
private fun findDataClass(): Class {
val dataClass = resolverInfoList.asSequence().map { it.dataClassType }.distinct().singleOrNull()
if (dataClass == null) {
throw ResolverError("Resolvers may not use the same type.")
} else {
return dataClass
}
}
override fun getFieldSearches(): List {
return resolverInfoList
.asSequence()
.map { FieldResolverScanner.Search(it.resolverType, this, it.resolver, dataClassType) }
.plus(FieldResolverScanner.Search(dataClassType, this, null))
.toList()
}
}
internal class RootResolverInfo(
val resolvers: List,
private val options: SchemaParserOptions
) : ResolverInfo() {
override fun getFieldSearches() =
resolvers.map { FieldResolverScanner.Search(getRealResolverClass(it, options), this, it) }
}
internal class DataClassResolverInfo(private val dataClass: JavaType) : ResolverInfo() {
override fun getFieldSearches() =
listOf(FieldResolverScanner.Search(dataClass, this, null))
}
internal class MissingResolverInfo : ResolverInfo() {
override fun getFieldSearches(): List = listOf()
}
internal class ResolverError(message: String, cause: Throwable? = null) : RuntimeException(message, cause)