All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.coxautodev.graphql.tools.Resolver.kt Maven / Gradle / Ivy

There is a newer version: 5.2.4
Show newest version
package com.coxautodev.graphql.tools

import com.google.common.collect.BiMap
import ru.vyarus.java.generics.resolver.GenericsResolver
import java.lang.reflect.Method

open class Resolver @JvmOverloads constructor(val resolver: GraphQLResolver<*>, dictionary: BiMap>, dataClass: Class<*>? = null) {

    val resolverType = resolver.javaClass
    val dataClassType = dataClass ?: findDataClass()
    val name = if(dataClassType != null) dictionary.inverse()[dataClassType] ?: dataClassType.simpleName!! else resolverType.simpleName!!

    private fun findDataClass(): Class<*>? {
        // Grab the parent interface with type GraphQLResolver from our resolver and get its first type argument.
        val type = GenericsResolver.resolve(resolverType).type(GraphQLResolver::class.java)?.genericTypes()?.first()

        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.")
        }

        return if(type != Void::class.java) type else null
    }

    private fun isBoolean(returnType: Class<*>): Boolean {
        return returnType.isAssignableFrom(Boolean::class.java) || returnType.isPrimitive && returnType.javaClass.name == "boolean"
    }

    private fun getMethod(clazz: Class<*>, name: String): Method? {
        val methods = clazz.methods

        // Check for the following one by one:
        //   1. Method with exact field name
        //   2. Method that returns a boolean with "is" style getter
        //   3. Method with "get" style getter
        return methods.find {
            it.name == name
        } ?: methods.find {
            (isBoolean(it.returnType) && it.name == "is${name.capitalize()}")
        } ?: methods.find {
            it.name == "get${name.capitalize()}"
        }
    }

    open fun getMethod(name: String): GetMethodResult {
        val method = getMethod(resolverType, name)

        if(method != null) {
            return GetMethodResult(method, resolverType, true)
        }

        return getDataClassMethod(name)
    }

    protected fun getDataClassMethod(name: String): GetMethodResult {
        if(dataClassType != null) {
            val method = getMethod(dataClassType, name)
            if(method != null) {
                return GetMethodResult(method, dataClassType, false)
            }
        }

        throw ResolverError(getMissingMethodMessage(name))
    }

    fun getMissingMethodMessage(name: String): String {
        var msg = "No method found with name: '$name' on "
        var hadResolver = false

        if(resolverType != NoopResolver::class.java) {
            msg += "resolver ${resolverType.name}"
            hadResolver = true
        }

        if(dataClassType != null) {
            if(hadResolver) {
                msg += " or its "
            }

            msg += "data class ${dataClassType.name}"
        }

        return msg
    }

    protected class NoopResolver: GraphQLRootResolver
    data class GetMethodResult(val method: Method, val methodClass: Class<*>, val resolverMethod: Boolean)
}

class NoResolver(dataClass: Class<*>, dictionary: BiMap>): Resolver(NoopResolver(), dictionary, dataClass) {
    override fun getMethod(name: String): GetMethodResult {
        return super.getDataClassMethod(name)
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy