Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 33 additions & 22 deletions src/main/kotlin/com/coxautodev/graphql/tools/MethodFieldResolver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ import java.util.*
/**
* @author Andrew Potter
*/
internal class MethodFieldResolver(field: FieldDefinition, search: FieldResolverScanner.Search, options: SchemaParserOptions, val method: Method): FieldResolver(field, search, options, method.declaringClass) {
internal class MethodFieldResolver(field: FieldDefinition, search: FieldResolverScanner.Search, options: SchemaParserOptions, val method: Method) : FieldResolver(field, search, options, method.declaringClass) {

companion object {
fun isBatched(method: Method, search: FieldResolverScanner.Search): Boolean {
if(method.getAnnotation(Batched::class.java) != null) {
if(!search.allowBatched) {
if (method.getAnnotation(Batched::class.java) != null) {
if (!search.allowBatched) {
throw ResolverError("The @Batched annotation is only allowed on non-root resolver methods, but it was found on ${search.type.name}#${method.name}!")
}

Expand All @@ -43,8 +43,8 @@ internal class MethodFieldResolver(field: FieldDefinition, search: FieldResolver
}.registerModule(Jdk8Module()).registerKotlinModule()

// Add source argument if this is a resolver (but not a root resolver)
if(this.search.requiredFirstParameterType != null) {
val expectedType = if(batched) Iterable::class.java else this.search.requiredFirstParameterType
if (this.search.requiredFirstParameterType != null) {
val expectedType = if (batched) Iterable::class.java else this.search.requiredFirstParameterType

args.add { environment ->
val source = environment.getSource<Any>()
Expand All @@ -59,23 +59,24 @@ internal class MethodFieldResolver(field: FieldDefinition, search: FieldResolver
// Add an argument for each argument defined in the GraphQL schema
this.field.inputValueDefinitions.forEachIndexed { index, definition ->

val genericParameterType = this.getJavaMethodParameterType(index) ?: throw ResolverError("Missing method type at position ${this.getJavaMethodParameterIndex(index)}, this is most likely a bug with graphql-java-tools")
val genericParameterType = this.getJavaMethodParameterType(index)
?: throw ResolverError("Missing method type at position ${this.getJavaMethodParameterIndex(index)}, this is most likely a bug with graphql-java-tools")

val isNonNull = definition.type is NonNullType
val isOptional = this.genericType.getRawClass(genericParameterType) == Optional::class.java

val typeReference = object: TypeReference<Any>() {
val typeReference = object : TypeReference<Any>() {
override fun getType() = genericParameterType
}

args.add { environment ->
val value = environment.arguments[definition.name] ?: if(isNonNull) {
val value = environment.arguments[definition.name] ?: if (isNonNull) {
throw ResolverError("Missing required argument with name '${definition.name}', this is most likely a bug with graphql-java-tools")
} else {
null
}

if(value == null && isOptional) {
if (value == null && isOptional) {
return@add Optional.empty<Any>()
}

Expand All @@ -84,16 +85,16 @@ internal class MethodFieldResolver(field: FieldDefinition, search: FieldResolver
}

// Add DataFetchingEnvironment/Context argument
if(this.additionalLastArgument) {
if (this.additionalLastArgument) {
val lastArgumentType = this.method.parameterTypes.last()
when(lastArgumentType) {
when (lastArgumentType) {
null -> throw ResolverError("Expected at least one argument but got none, this is most likely a bug with graphql-java-tools")
options.contextClass -> args.add { environment -> environment.getContext() }
else -> args.add { environment -> environment }
}
}

return if(batched) {
return if (batched) {
BatchedMethodFieldResolverDataFetcher(getSourceResolver(), this.method, args, options)
} else {
MethodFieldResolverDataFetcher(getSourceResolver(), this.method, args, options)
Expand All @@ -109,14 +110,14 @@ internal class MethodFieldResolver(field: FieldDefinition, search: FieldResolver
} + listOf(returnValueMatch)
}

private fun getIndexOffset() = if(resolverInfo is NormalResolverInfo) 1 else 0
private fun getIndexOffset() = if (resolverInfo is NormalResolverInfo) 1 else 0
private fun getJavaMethodParameterIndex(index: Int) = index + getIndexOffset()

private fun getJavaMethodParameterType(index: Int): JavaType? {
val methodIndex = getJavaMethodParameterIndex(index)
val parameters = method.parameterTypes

return if(parameters.size > methodIndex) {
return if (parameters.size > methodIndex) {
method.genericParameterTypes[getJavaMethodParameterIndex(index)]
} else {
null
Expand All @@ -126,14 +127,14 @@ internal class MethodFieldResolver(field: FieldDefinition, search: FieldResolver
override fun toString() = "MethodFieldResolver{method=$method}"
}

open class MethodFieldResolverDataFetcher(private val sourceResolver: SourceResolver, method: Method, private val args: List<ArgumentPlaceholder>, private val options: SchemaParserOptions): DataFetcher<Any> {
open class MethodFieldResolverDataFetcher(private val sourceResolver: SourceResolver, method: Method, private val args: List<ArgumentPlaceholder>, private val options: SchemaParserOptions) : DataFetcher<Any> {

// Convert to reflactasm reflection
private val methodAccess = MethodAccess.get(method.declaringClass)!!
private val methodIndex = methodAccess.getIndex(method.name, *method.parameterTypes)

private class CompareGenericWrappers {
companion object: Comparator<GenericWrapper> {
companion object : Comparator<GenericWrapper> {
override fun compare(w1: GenericWrapper, w2: GenericWrapper): Int = when {
w1.type.isAssignableFrom(w2.type) -> 1
else -> -1
Expand All @@ -149,21 +150,31 @@ open class MethodFieldResolverDataFetcher(private val sourceResolver: SourceReso
result
} else {
val wrapper = options
.genericWrappers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should cs fixes be included in feature pr?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im using intellij and when I push it fixes lines automatically.
It's only cs fixes, so it doesn't matter

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, that actually matters because

  • it makes PR more lines to read
  • the PR affects lines that have nothing to do with the feature, meaning it's more difficult to find why/when the initial fix was made

Just saying, no cs configuration is included in the project anyway.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. so I won't do it next time

.filter { it.type.isInstance(result) }
.sortedWith(CompareGenericWrappers)
.firstOrNull()
.genericWrappers
.filter { it.type.isInstance(result) }
.sortedWith(CompareGenericWrappers)
.firstOrNull()
if (wrapper == null) {
result
} else {
wrapper.transformer.invoke(result, environment)
}
}
}

/**
* Function that return the object used to fetch the data
* It can be a DataFetcher or an entity
*/
@Suppress("unused")
open fun getWrappedFetchingObject(environment: DataFetchingEnvironment): Any {
return sourceResolver(environment)
}
}

class BatchedMethodFieldResolverDataFetcher(sourceResolver: SourceResolver, method: Method, args: List<ArgumentPlaceholder>, options: SchemaParserOptions): MethodFieldResolverDataFetcher(sourceResolver, method, args, options) {
@Batched override fun get(environment: DataFetchingEnvironment) = super.get(environment)
class BatchedMethodFieldResolverDataFetcher(sourceResolver: SourceResolver, method: Method, args: List<ArgumentPlaceholder>, options: SchemaParserOptions) : MethodFieldResolverDataFetcher(sourceResolver, method, args, options) {
@Batched
override fun get(environment: DataFetchingEnvironment) = super.get(environment)
}

internal typealias ArgumentPlaceholder = (DataFetchingEnvironment) -> Any?
Expand Down