From 213f8443aa5529388709c576d2d17df2ad09b375 Mon Sep 17 00:00:00 2001 From: Vojtech Polivka Date: Fri, 27 Sep 2024 14:04:53 -0700 Subject: [PATCH 01/12] Upgrade to v22.x --- pom.xml | 4 ++- .../kickstart/tools/resolver/FieldResolver.kt | 1 + .../tools/resolver/MethodFieldResolver.kt | 25 ++++++++++++------- .../kickstart/tools/EndToEndSpecHelper.kt | 5 ++-- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index 555e0846..3525ddc1 100644 --- a/pom.xml +++ b/pom.xml @@ -45,7 +45,7 @@ com.graphql-java graphql-java - ${graphql-java.version} + 22.1 org.antlr @@ -306,6 +306,8 @@ **/*Test.* + + --add-reads kotlin.stdlib=kotlinx.coroutines.core diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolver.kt index af88f6aa..440d4473 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolver.kt @@ -35,6 +35,7 @@ internal abstract class FieldResolver( } else { { environment -> val source = environment.getSource() + ?: throw ResolverError("Expected source object to not be null!") if (!this.genericType.isAssignableFrom(source.javaClass)) { throw ResolverError("Expected source object to be an instance of '${this.genericType.getRawClass().name}' but instead got '${source.javaClass.name}'") diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt index c76023d5..ebcb4a52 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt @@ -30,7 +30,7 @@ internal class MethodFieldResolver( field: FieldDefinition, search: FieldResolverScanner.Search, options: SchemaParserOptions, - val method: Method + val method: Method, ) : FieldResolver(field, search, options, search.type) { private val log = LoggerFactory.getLogger(javaClass) @@ -53,6 +53,7 @@ internal class MethodFieldResolver( args.add { environment -> val source = environment.getSource() + ?: throw ResolverError("Expected source object to not be null!") if (!expectedType.isAssignableFrom(source.javaClass)) { throw ResolverError("Source type (${source.javaClass.name}) is not expected type (${expectedType.name})!") } @@ -114,6 +115,7 @@ internal class MethodFieldResolver( environment.getContext() // TODO: remove deprecated use in next major release } } + GraphQLContext::class.java -> args.add { environment -> environment.graphQlContext } else -> args.add { environment -> environment } } @@ -139,19 +141,23 @@ internal class MethodFieldResolver( return when (type) { is ListType -> List::class.java.isAssignableFrom(this.genericType.getRawClass(genericParameterType)) && isConcreteScalarType(environment, type.type, this.genericType.unwrapGenericType(genericParameterType)) + is TypeName -> environment.graphQLSchema?.getType(type.name)?.let { isScalar(it) && type.name != "ID" } ?: false + is NonNullType -> isConcreteScalarType(environment, type.type, genericParameterType) else -> false } } override fun scanForMatches(): List { - val unwrappedGenericType = genericType.unwrapGenericType(try { - method.kotlinFunction?.returnType?.javaType ?: method.genericReturnType - } catch (e: InternalError) { - method.genericReturnType - }) + val unwrappedGenericType = genericType.unwrapGenericType( + try { + method.kotlinFunction?.returnType?.javaType ?: method.genericReturnType + } catch (e: InternalError) { + method.genericReturnType + } + ) val returnValueMatch = TypeClassMatcher.PotentialMatch.returnValue(field.type, unwrappedGenericType, genericType, SchemaClassScanner.ReturnValueReference(method)) return field.inputValueDefinitions.mapIndexed { i, inputDefinition -> @@ -187,7 +193,7 @@ internal open class MethodFieldResolverDataFetcher( private val sourceResolver: SourceResolver, method: Method, private val args: List, - private val options: SchemaParserOptions + private val options: SchemaParserOptions, ) : DataFetcher { private val resolverMethod = method @@ -238,11 +244,12 @@ internal open class MethodFieldResolverDataFetcher( } } +// TODO use graphql.schema.LightDataFetcher internal class TrivialMethodFieldResolverDataFetcher( sourceResolver: SourceResolver, method: Method, args: List, - options: SchemaParserOptions + options: SchemaParserOptions, ) : MethodFieldResolverDataFetcher(sourceResolver, method, args, options), TrivialDataFetcher // just to mark it for tracing and optimizations @@ -256,7 +263,7 @@ private fun invoke(method: Method, instance: Any, args: Array): Any? { try { return method.invoke(instance, *args) } catch (e: InvocationTargetException) { - throw e.cause ?: RuntimeException("Unknown error occurred while invoking resolver method") + throw e.cause ?: RuntimeException("Unknown error occurred while invoking resolver method") } } diff --git a/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt b/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt index 329f9ed8..b728f7a0 100644 --- a/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt +++ b/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt @@ -141,8 +141,8 @@ input ItemSearchInput { } input NewItemInput { - name: String! @deprecated - type: Type! @deprecated(reason: "This is a reason") + name: String @deprecated + type: Type @deprecated(reason: "This is a reason") } enum Type { @@ -536,4 +536,3 @@ val uploadScalar: GraphQLScalarType = GraphQLScalarType.newScalar() throw CoercingParseLiteralException("Must use variables to specify Upload values") } }).build() - From 5b309bb27a7034e9c1af9724a9ed010b58bc2317 Mon Sep 17 00:00:00 2001 From: Vojtech Polivka Date: Tue, 1 Oct 2024 08:28:19 -0700 Subject: [PATCH 02/12] Upgrade to v22.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3525ddc1..acaf46f9 100644 --- a/pom.xml +++ b/pom.xml @@ -45,7 +45,7 @@ com.graphql-java graphql-java - 22.1 + 22.3 org.antlr From f19e0369b6b273e789d40c4544884ea897f43688 Mon Sep 17 00:00:00 2001 From: Vojtech Polivka Date: Tue, 1 Oct 2024 14:54:51 -0700 Subject: [PATCH 03/12] Upgrade other dependencies --- pom.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index acaf46f9..685a8f7a 100644 --- a/pom.xml +++ b/pom.xml @@ -14,10 +14,10 @@ UTF-8 11 - 1.8.21 - 1.7.3 - 2.16.0 - 21.3 + 2.0.20 + 1.9.0 + 2.17.0 + 22.3 1.0.4 ${java.version} @@ -45,7 +45,7 @@ com.graphql-java graphql-java - 22.3 + ${graphql-java.version} org.antlr @@ -83,7 +83,7 @@ 3.29.2-GA provided - + org.springframework spring-aop @@ -91,7 +91,7 @@ provided - + cglib cglib-nodep @@ -134,8 +134,8 @@ org.jetbrains.kotlin kotlin-stdlib - + org.jetbrains annotations @@ -306,7 +306,7 @@ **/*Test.* - + --add-reads kotlin.stdlib=kotlinx.coroutines.core From 834afeaaa0ee0a56fa587550267c8a141492c94c Mon Sep 17 00:00:00 2001 From: Vojtech Polivka Date: Tue, 1 Oct 2024 15:57:38 -0700 Subject: [PATCH 04/12] Use LightDataFetcher where possible --- pom.xml | 2 +- .../kickstart/tools/resolver/FieldResolver.kt | 22 +++- .../tools/resolver/MapFieldResolver.kt | 20 +-- .../tools/resolver/MethodFieldResolver.kt | 117 ++++++++++++------ .../tools/resolver/PropertyFieldResolver.kt | 20 ++- .../graphql/kickstart/tools/util/Utils.kt | 7 +- .../graphql/kickstart/tools/DirectiveTest.kt | 1 + .../MethodFieldResolverDataFetcherTest.kt | 8 ++ .../graphql/kickstart/tools/TestUtils.kt | 14 ++- 9 files changed, 140 insertions(+), 71 deletions(-) diff --git a/pom.xml b/pom.xml index 685a8f7a..2944adf8 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.graphql-java-kickstart graphql-java-tools - 13.1.2-SNAPSHOT + 14.0.0-LOCAL jar GraphQL Java Tools diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolver.kt index 440d4473..440820c8 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolver.kt @@ -29,13 +29,20 @@ internal abstract class FieldResolver( /** * Add source resolver depending on whether or not this is a resolver method */ - protected fun getSourceResolver(): SourceResolver { + protected fun createSourceResolver(): SourceResolver { return if (this.search.source != null) { - { this.search.source } + SourceResolver { _, _ -> this.search.source } } else { - { environment -> - val source = environment.getSource() - ?: throw ResolverError("Expected source object to not be null!") + SourceResolver { environment, sourceObject -> + val source = if (sourceObject != null) { + // if source object is known, environment is null as an optimization (LightDataFetcher) + sourceObject + } else { + environment + ?: throw ResolverError("Expected DataFetchingEnvironment to not be null!") + environment.getSource() + ?: throw ResolverError("Expected source object to not be null!") + } if (!this.genericType.isAssignableFrom(source.javaClass)) { throw ResolverError("Expected source object to be an instance of '${this.genericType.getRawClass().name}' but instead got '${source.javaClass.name}'") @@ -47,4 +54,7 @@ internal abstract class FieldResolver( } } -internal typealias SourceResolver = (DataFetchingEnvironment) -> Any +fun interface SourceResolver { + + fun resolve(environment: DataFetchingEnvironment?, source: Any?): Any +} diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/MapFieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/MapFieldResolver.kt index 20e51a24..d7d29f5c 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/MapFieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/MapFieldResolver.kt @@ -8,6 +8,9 @@ import graphql.kickstart.tools.util.JavaType import graphql.language.FieldDefinition import graphql.schema.DataFetcher import graphql.schema.DataFetchingEnvironment +import graphql.schema.GraphQLFieldDefinition +import graphql.schema.LightDataFetcher +import java.util.function.Supplier /** * @author Nick Weedon @@ -37,7 +40,7 @@ internal class MapFieldResolver( } override fun createDataFetcher(): DataFetcher<*> { - return MapFieldResolverDataFetcher(getSourceResolver(), field.name) + return MapFieldResolverDataFetcher(createSourceResolver(), field.name) } override fun scanForMatches(): List { @@ -49,15 +52,18 @@ internal class MapFieldResolver( internal class MapFieldResolverDataFetcher( private val sourceResolver: SourceResolver, - private val key: String -) : DataFetcher { + private val key: String, +) : LightDataFetcher { - override fun get(environment: DataFetchingEnvironment): Any? { - val resolvedSourceObject = sourceResolver(environment) - if (resolvedSourceObject is Map<*, *>) { - return resolvedSourceObject[key] + override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any, environmentSupplier: Supplier): Any? { + if (sourceObject is Map<*, *>) { + return sourceObject[key] } else { throw RuntimeException("MapFieldResolver attempt to fetch a field from an object instance that was not a map") } } + + override fun get(environment: DataFetchingEnvironment): Any? { + return get(environment.fieldDefinition, sourceResolver.resolve(environment, null), { environment }) + } } diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt index ebcb4a52..3ae84c0c 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt @@ -2,7 +2,6 @@ package graphql.kickstart.tools.resolver import com.fasterxml.jackson.core.type.TypeReference import graphql.GraphQLContext -import graphql.TrivialDataFetcher import graphql.kickstart.tools.* import graphql.kickstart.tools.SchemaParserOptions.GenericWrapper import graphql.kickstart.tools.util.JavaType @@ -12,12 +11,15 @@ import graphql.kickstart.tools.util.unwrap import graphql.language.* import graphql.schema.DataFetcher import graphql.schema.DataFetchingEnvironment +import graphql.schema.GraphQLFieldDefinition import graphql.schema.GraphQLTypeUtil.isScalar +import graphql.schema.LightDataFetcher import kotlinx.coroutines.future.future import org.slf4j.LoggerFactory import java.lang.reflect.InvocationTargetException import java.lang.reflect.Method import java.util.* +import java.util.function.Supplier import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn import kotlin.reflect.full.valueParameters import kotlin.reflect.jvm.javaType @@ -122,9 +124,9 @@ internal class MethodFieldResolver( } return if (args.isEmpty() && isTrivialDataFetcher(this.method)) { - TrivialMethodFieldResolverDataFetcher(getSourceResolver(), this.method, args, options) + LightMethodFieldResolverDataFetcher(createSourceResolver(), this.method, options) } else { - MethodFieldResolverDataFetcher(getSourceResolver(), this.method, args, options) + MethodFieldResolverDataFetcher(createSourceResolver(), this.method, args, options) } } @@ -189,69 +191,102 @@ internal class MethodFieldResolver( override fun toString() = "MethodFieldResolver{method=$method}" } -internal open class MethodFieldResolverDataFetcher( +internal class MethodFieldResolverDataFetcher( private val sourceResolver: SourceResolver, - method: Method, + private val method: Method, private val args: List, private val options: SchemaParserOptions, ) : DataFetcher { - private val resolverMethod = method - private val isSuspendFunction = try { - method.kotlinFunction?.isSuspend == true - } catch (e: InternalError) { - false - } + private val isSuspendFunction = method.isSuspendFunction() - private class CompareGenericWrappers { - companion object : Comparator { - override fun compare(w1: GenericWrapper, w2: GenericWrapper): Int = when { - w1.type.isAssignableFrom(w2.type) -> 1 - else -> -1 + override fun get(environment: DataFetchingEnvironment): Any? { + val source = sourceResolver.resolve(environment, null) + val args = this.args.map { it(environment) }.toTypedArray() + + return if (isSuspendFunction) { + environment.coroutineScope().future(options.coroutineContextProvider.provide()) { + invokeSuspend(source, method, args)?.transformWithGenericWrapper(options.genericWrappers, { environment }) } + } else { + invoke(method, source, args)?.transformWithGenericWrapper(options.genericWrappers, { environment }) } } - override fun get(environment: DataFetchingEnvironment): Any? { - val source = sourceResolver(environment) - val args = this.args.map { it(environment) }.toTypedArray() + /** + * Function that returns the object used to fetch the data. It can be a DataFetcher or an entity. + */ + @Suppress("unused") + fun getWrappedFetchingObject(environment: DataFetchingEnvironment): Any { + return sourceResolver.resolve(environment, null) + } +} + +/** + * Similar to [MethodFieldResolverDataFetcher] but for light data fetchers which do not require the environment to be supplied unless suspend functions or + * generic wrappers are used. + */ +internal class LightMethodFieldResolverDataFetcher( + private val sourceResolver: SourceResolver, + private val method: Method, + private val options: SchemaParserOptions, +) : LightDataFetcher { + + private val isSuspendFunction = method.isSuspendFunction() + + override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any, environmentSupplier: Supplier): Any? { + val source = sourceResolver.resolve(null, sourceObject) return if (isSuspendFunction) { - environment.coroutineScope().future(options.coroutineContextProvider.provide()) { - invokeSuspend(source, resolverMethod, args)?.transformWithGenericWrapper(environment) + environmentSupplier.get().coroutineScope().future(options.coroutineContextProvider.provide()) { + invokeSuspend(source, method, emptyArray())?.transformWithGenericWrapper(options.genericWrappers, environmentSupplier) } } else { - invoke(resolverMethod, source, args)?.transformWithGenericWrapper(environment) + invoke(method, source, emptyArray())?.transformWithGenericWrapper(options.genericWrappers, environmentSupplier) } } - private fun Any.transformWithGenericWrapper(environment: DataFetchingEnvironment): Any? { - return options.genericWrappers - .asSequence() - .filter { it.type.isInstance(this) } - .sortedWith(CompareGenericWrappers) - .firstOrNull() - ?.transformer?.invoke(this, environment) ?: this + override fun get(environment: DataFetchingEnvironment): Any? { + return get(environment.fieldDefinition, sourceResolver.resolve(environment, null), { environment }) } /** - * Function that returns the object used to fetch the data. - * It can be a DataFetcher or an entity. + * Function that returns 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) + fun getWrappedFetchingObject(environment: DataFetchingEnvironment): Any { + return sourceResolver.resolve(environment, null) } } -// TODO use graphql.schema.LightDataFetcher -internal class TrivialMethodFieldResolverDataFetcher( - sourceResolver: SourceResolver, - method: Method, - args: List, - options: SchemaParserOptions, -) : MethodFieldResolverDataFetcher(sourceResolver, method, args, options), - TrivialDataFetcher // just to mark it for tracing and optimizations +private fun Any.transformWithGenericWrapper( + genericWrappers: List, + environmentSupplier: Supplier +): Any? { + return genericWrappers + .asSequence() + .filter { it.type.isInstance(this) } + .sortedWith(CompareGenericWrappers) + .firstOrNull() + ?.transformer?.invoke(this, environmentSupplier.get()) ?: this +} + +private class CompareGenericWrappers { + companion object : Comparator { + override fun compare(w1: GenericWrapper, w2: GenericWrapper): Int = when { + w1.type.isAssignableFrom(w2.type) -> 1 + else -> -1 + } + } +} + +private fun Method.isSuspendFunction(): Boolean { + return try { + this.kotlinFunction?.isSuspend == true + } catch (e: InternalError) { + false + } +} private suspend inline fun invokeSuspend(target: Any, resolverMethod: Method, args: Array): Any? { return suspendCoroutineUninterceptedOrReturn { continuation -> diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/PropertyFieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/PropertyFieldResolver.kt index dba3e9dd..96c8953e 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/PropertyFieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/PropertyFieldResolver.kt @@ -6,7 +6,10 @@ import graphql.kickstart.tools.TypeClassMatcher import graphql.language.FieldDefinition import graphql.schema.DataFetcher import graphql.schema.DataFetchingEnvironment +import graphql.schema.GraphQLFieldDefinition +import graphql.schema.LightDataFetcher import java.lang.reflect.Field +import java.util.function.Supplier /** * @author Andrew Potter @@ -15,11 +18,11 @@ internal class PropertyFieldResolver( field: FieldDefinition, search: FieldResolverScanner.Search, options: SchemaParserOptions, - private val property: Field + private val property: Field, ) : FieldResolver(field, search, options, property.declaringClass) { override fun createDataFetcher(): DataFetcher<*> { - return PropertyFieldResolverDataFetcher(getSourceResolver(), property) + return PropertyFieldResolverDataFetcher(createSourceResolver(), property) } override fun scanForMatches(): List { @@ -28,7 +31,8 @@ internal class PropertyFieldResolver( field.type, property.genericType, genericType, - SchemaClassScanner.FieldTypeReference(property.toString())) + SchemaClassScanner.FieldTypeReference(property.toString()) + ) ) } @@ -37,10 +41,14 @@ internal class PropertyFieldResolver( internal class PropertyFieldResolverDataFetcher( private val sourceResolver: SourceResolver, - private val field: Field -) : DataFetcher { + private val field: Field, +) : LightDataFetcher { + + override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any, environmentSupplier: Supplier): Any? { + return field.get(sourceResolver.resolve(null, sourceObject)) + } override fun get(environment: DataFetchingEnvironment): Any? { - return field.get(sourceResolver(environment)) + return get(environment.fieldDefinition, sourceResolver.resolve(environment, null), { environment }) } } diff --git a/src/main/kotlin/graphql/kickstart/tools/util/Utils.kt b/src/main/kotlin/graphql/kickstart/tools/util/Utils.kt index ba5e22a5..f1802402 100644 --- a/src/main/kotlin/graphql/kickstart/tools/util/Utils.kt +++ b/src/main/kotlin/graphql/kickstart/tools/util/Utils.kt @@ -62,11 +62,11 @@ internal fun getDocumentation(node: AbstractNode<*>, options: SchemaParserOption } /** - * Simple heuristic to check is a method is a trivial data fetcher. + * Simple heuristic to check if a method is a trivial data fetcher. * * Requirements are: - * prefixed with get - * must have zero parameters + * - prefixed with get + * - must have zero parameters */ internal fun isTrivialDataFetcher(method: Method): Boolean { return (method.parameterCount == 0 @@ -80,4 +80,3 @@ private fun isBooleanGetter(method: Method) = (method.name.startsWith("is") || method.returnType == Boolean::class.java) internal fun String.snakeToCamelCase(): String = split("_").joinToString(separator = "") { it.replaceFirstChar(Char::titlecase) } - diff --git a/src/test/kotlin/graphql/kickstart/tools/DirectiveTest.kt b/src/test/kotlin/graphql/kickstart/tools/DirectiveTest.kt index 912b3501..79e787cf 100644 --- a/src/test/kotlin/graphql/kickstart/tools/DirectiveTest.kt +++ b/src/test/kotlin/graphql/kickstart/tools/DirectiveTest.kt @@ -10,6 +10,7 @@ import graphql.schema.idl.SchemaDirectiveWiringEnvironment import org.junit.Test class DirectiveTest { + @Test fun `should apply @uppercase directive on field`() { val schema = SchemaParser.newParser() diff --git a/src/test/kotlin/graphql/kickstart/tools/MethodFieldResolverDataFetcherTest.kt b/src/test/kotlin/graphql/kickstart/tools/MethodFieldResolverDataFetcherTest.kt index 481d2a4e..9401feef 100644 --- a/src/test/kotlin/graphql/kickstart/tools/MethodFieldResolverDataFetcherTest.kt +++ b/src/test/kotlin/graphql/kickstart/tools/MethodFieldResolverDataFetcherTest.kt @@ -13,6 +13,8 @@ import graphql.language.TypeName import graphql.schema.DataFetcher import graphql.schema.DataFetchingEnvironment import graphql.schema.DataFetchingEnvironmentImpl +import graphql.schema.GraphQLFieldDefinition +import graphql.schema.GraphQLObjectType import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job @@ -299,6 +301,12 @@ class MethodFieldResolverDataFetcherTest { private fun createEnvironment(source: Any = Object(), arguments: Map = emptyMap(), context: GraphQLContext? = null): DataFetchingEnvironment { return DataFetchingEnvironmentImpl.newDataFetchingEnvironment(buildExecutionContext()) .source(source) + .fieldDefinition( + GraphQLFieldDefinition.newFieldDefinition() + .name("ignored") + .type(GraphQLObjectType.newObject().name("ignored").build()) + .build() + ) .arguments(arguments) .graphQLContext(context) .build() diff --git a/src/test/kotlin/graphql/kickstart/tools/TestUtils.kt b/src/test/kotlin/graphql/kickstart/tools/TestUtils.kt index 2b0ff09b..32473510 100644 --- a/src/test/kotlin/graphql/kickstart/tools/TestUtils.kt +++ b/src/test/kotlin/graphql/kickstart/tools/TestUtils.kt @@ -7,14 +7,16 @@ import graphql.GraphQL private val mapper = ObjectMapper() fun assertNoGraphQlErrors(gql: GraphQL, args: Map = mapOf(), context: Map = mapOf(), closure: () -> String): Map { - val result = gql.execute(ExecutionInput.newExecutionInput() - .query(closure.invoke()) - .graphQLContext(context) - .root(context) - .variables(args)) + val result = gql.execute( + ExecutionInput.newExecutionInput() + .query(closure.invoke()) + .graphQLContext(context) + .root(context) + .variables(args) + ) if (result.errors.isNotEmpty()) { - throw AssertionError("GraphQL result contained errors!\n${result.errors.map { mapper.writeValueAsString(it) }.joinToString { "\n" }}") + throw AssertionError("GraphQL result contained errors!\n${result.errors.map { it.message }.joinToString("\n")}") } return result.getData() as Map From 29cecf01ca6e7eb68fd3d06cdf6b42d3473113d5 Mon Sep 17 00:00:00 2001 From: Vojtech Polivka Date: Wed, 2 Oct 2024 13:06:03 -0700 Subject: [PATCH 05/12] Downgrade build-helper-maven-plugin to 3.4.0 to fix JitPack build --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2944adf8..bd3d7db2 100644 --- a/pom.xml +++ b/pom.xml @@ -240,7 +240,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.5.0 + 3.4.0 add-test-source From 0745d59b4fd261de22655521dd56d3b064eacc6e Mon Sep 17 00:00:00 2001 From: Vojtech Polivka Date: Thu, 3 Oct 2024 09:15:55 -0700 Subject: [PATCH 06/12] Simplify lightweight data fetcher heuristic --- pom.xml | 2 +- .../tools/resolver/MapFieldResolver.kt | 2 +- .../tools/resolver/MethodFieldResolver.kt | 39 +++++++------------ .../tools/resolver/PropertyFieldResolver.kt | 2 +- .../graphql/kickstart/tools/util/Utils.kt | 18 --------- .../graphql/kickstart/tools/util/UtilsTest.kt | 18 --------- 6 files changed, 16 insertions(+), 65 deletions(-) diff --git a/pom.xml b/pom.xml index bd3d7db2..f23b3ee4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.graphql-java-kickstart graphql-java-tools - 14.0.0-LOCAL + 14.1.0-LOCAL jar GraphQL Java Tools diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/MapFieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/MapFieldResolver.kt index d7d29f5c..ce48e494 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/MapFieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/MapFieldResolver.kt @@ -55,7 +55,7 @@ internal class MapFieldResolverDataFetcher( private val key: String, ) : LightDataFetcher { - override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any, environmentSupplier: Supplier): Any? { + override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any?, environmentSupplier: Supplier): Any? { if (sourceObject is Map<*, *>) { return sourceObject[key] } else { diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt index 3ae84c0c..a400b1e7 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt @@ -6,7 +6,6 @@ import graphql.kickstart.tools.* import graphql.kickstart.tools.SchemaParserOptions.GenericWrapper import graphql.kickstart.tools.util.JavaType import graphql.kickstart.tools.util.coroutineScope -import graphql.kickstart.tools.util.isTrivialDataFetcher import graphql.kickstart.tools.util.unwrap import graphql.language.* import graphql.schema.DataFetcher @@ -37,13 +36,9 @@ internal class MethodFieldResolver( private val log = LoggerFactory.getLogger(javaClass) - private val additionalLastArgument = - try { - (method.kotlinFunction?.valueParameters?.size - ?: method.parameterCount) == (field.inputValueDefinitions.size + getIndexOffset() + 1) - } catch (e: InternalError) { - method.parameterCount == (field.inputValueDefinitions.size + getIndexOffset() + 1) - } + private val isSuspendFunction = method.isSuspendFunction() + private val numberOfParameters = method.kotlinFunction?.valueParameters?.size ?: method.parameterCount + private val hasAdditionalParameter = numberOfParameters == (field.inputValueDefinitions.size + getIndexOffset() + 1) override fun createDataFetcher(): DataFetcher<*> { val args = mutableListOf() @@ -100,7 +95,7 @@ internal class MethodFieldResolver( } // Add DataFetchingEnvironment/Context argument - if (this.additionalLastArgument) { + if (this.hasAdditionalParameter) { when (this.method.parameterTypes.last()) { 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 -> @@ -123,10 +118,12 @@ internal class MethodFieldResolver( } } - return if (args.isEmpty() && isTrivialDataFetcher(this.method)) { - LightMethodFieldResolverDataFetcher(createSourceResolver(), this.method, options) + return if (numberOfParameters > 0 || isSuspendFunction) { + // requires arguments and environment or is a suspend function + MethodFieldResolverDataFetcher(createSourceResolver(), this.method, args, options, isSuspendFunction) } else { - MethodFieldResolverDataFetcher(createSourceResolver(), this.method, args, options) + // if there are no parameters an optimized version of the data fetcher can be used + LightMethodFieldResolverDataFetcher(createSourceResolver(), this.method, options) } } @@ -196,10 +193,9 @@ internal class MethodFieldResolverDataFetcher( private val method: Method, private val args: List, private val options: SchemaParserOptions, + private val isSuspendFunction: Boolean ) : DataFetcher { - private val isSuspendFunction = method.isSuspendFunction() - override fun get(environment: DataFetchingEnvironment): Any? { val source = sourceResolver.resolve(environment, null) val args = this.args.map { it(environment) }.toTypedArray() @@ -223,8 +219,7 @@ internal class MethodFieldResolverDataFetcher( } /** - * Similar to [MethodFieldResolverDataFetcher] but for light data fetchers which do not require the environment to be supplied unless suspend functions or - * generic wrappers are used. + * Similar to [MethodFieldResolverDataFetcher] but for light data fetchers which do not require the environment to be supplied unless generic wrappers are used. */ internal class LightMethodFieldResolverDataFetcher( private val sourceResolver: SourceResolver, @@ -232,18 +227,10 @@ internal class LightMethodFieldResolverDataFetcher( private val options: SchemaParserOptions, ) : LightDataFetcher { - private val isSuspendFunction = method.isSuspendFunction() - - override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any, environmentSupplier: Supplier): Any? { + override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any?, environmentSupplier: Supplier): Any? { val source = sourceResolver.resolve(null, sourceObject) - return if (isSuspendFunction) { - environmentSupplier.get().coroutineScope().future(options.coroutineContextProvider.provide()) { - invokeSuspend(source, method, emptyArray())?.transformWithGenericWrapper(options.genericWrappers, environmentSupplier) - } - } else { - invoke(method, source, emptyArray())?.transformWithGenericWrapper(options.genericWrappers, environmentSupplier) - } + return invoke(method, source, emptyArray())?.transformWithGenericWrapper(options.genericWrappers, environmentSupplier) } override fun get(environment: DataFetchingEnvironment): Any? { diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/PropertyFieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/PropertyFieldResolver.kt index 96c8953e..afbb29f3 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/PropertyFieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/PropertyFieldResolver.kt @@ -44,7 +44,7 @@ internal class PropertyFieldResolverDataFetcher( private val field: Field, ) : LightDataFetcher { - override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any, environmentSupplier: Supplier): Any? { + override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any?, environmentSupplier: Supplier): Any? { return field.get(sourceResolver.resolve(null, sourceObject)) } diff --git a/src/main/kotlin/graphql/kickstart/tools/util/Utils.kt b/src/main/kotlin/graphql/kickstart/tools/util/Utils.kt index f1802402..e61e88c9 100644 --- a/src/main/kotlin/graphql/kickstart/tools/util/Utils.kt +++ b/src/main/kotlin/graphql/kickstart/tools/util/Utils.kt @@ -61,22 +61,4 @@ internal fun getDocumentation(node: AbstractNode<*>, options: SchemaParserOption .trimIndent() } -/** - * Simple heuristic to check if a method is a trivial data fetcher. - * - * Requirements are: - * - prefixed with get - * - must have zero parameters - */ -internal fun isTrivialDataFetcher(method: Method): Boolean { - return (method.parameterCount == 0 - && ( - method.name.startsWith("get") - || isBooleanGetter(method))) -} - -private fun isBooleanGetter(method: Method) = (method.name.startsWith("is") - && (method.returnType == java.lang.Boolean::class.java) - || method.returnType == Boolean::class.java) - internal fun String.snakeToCamelCase(): String = split("_").joinToString(separator = "") { it.replaceFirstChar(Char::titlecase) } diff --git a/src/test/kotlin/graphql/kickstart/tools/util/UtilsTest.kt b/src/test/kotlin/graphql/kickstart/tools/util/UtilsTest.kt index e8af532e..14cd8dd9 100644 --- a/src/test/kotlin/graphql/kickstart/tools/util/UtilsTest.kt +++ b/src/test/kotlin/graphql/kickstart/tools/util/UtilsTest.kt @@ -1,8 +1,5 @@ package graphql.kickstart.tools.util -import org.junit.Assert -import org.junit.Test - class UtilsTest { @Suppress("unused") @@ -26,19 +23,4 @@ class UtilsTest { private class UtilsTestTrivialDataFetcherBean { val isBooleanPrimitive = false } - - @Test - fun isTrivialDataFetcher() { - val clazz = Bean::class.java - - Assert.assertTrue(isTrivialDataFetcher(clazz.getMethod("getterValid"))) - Assert.assertFalse(isTrivialDataFetcher(clazz.getMethod("getterWithArgument", String::class.java))) - Assert.assertFalse(isTrivialDataFetcher(clazz.getMethod("notAGetter"))) - - Assert.assertFalse(isTrivialDataFetcher(clazz.getMethod("isString"))) - Assert.assertTrue(isTrivialDataFetcher(clazz.getMethod("isJavaBoolean"))) - Assert.assertTrue(isTrivialDataFetcher(clazz.getMethod("isKotlinBoolean"))) - - Assert.assertTrue(isTrivialDataFetcher(UtilsTestTrivialDataFetcherBean::class.java.getMethod("isBooleanPrimitive"))) - } } From edafe516d9e4739f660334bd4ee8e297f4a6a401 Mon Sep 17 00:00:00 2001 From: Vojtech Polivka Date: Thu, 3 Oct 2024 10:12:47 -0700 Subject: [PATCH 07/12] Adjust comments --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f23b3ee4..2479b230 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.graphql-java-kickstart graphql-java-tools - 14.1.0-LOCAL + 14.2.0-LOCAL jar GraphQL Java Tools @@ -240,6 +240,7 @@ org.codehaus.mojo build-helper-maven-plugin + 3.4.0 @@ -306,7 +307,6 @@ **/*Test.* - --add-reads kotlin.stdlib=kotlinx.coroutines.core From e5ca52b724e588aa379c97732740c80f97ed8626 Mon Sep 17 00:00:00 2001 From: Oryan Date: Mon, 7 Oct 2024 13:08:34 -0400 Subject: [PATCH 08/12] Reformat --- .../kickstart/tools/resolver/FieldResolver.kt | 17 ++++------------- .../tools/resolver/MapFieldResolver.kt | 4 ++-- .../tools/resolver/MethodFieldResolver.kt | 12 ++++++------ .../tools/resolver/PropertyFieldResolver.kt | 6 +++--- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolver.kt index 440820c8..addf61d7 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolver.kt @@ -1,10 +1,6 @@ package graphql.kickstart.tools.resolver import graphql.kickstart.tools.* -import graphql.kickstart.tools.GenericType -import graphql.kickstart.tools.ResolverError -import graphql.kickstart.tools.ResolverInfo -import graphql.kickstart.tools.TypeClassMatcher import graphql.kickstart.tools.util.JavaType import graphql.language.FieldDefinition import graphql.schema.DataFetcher @@ -34,15 +30,10 @@ internal abstract class FieldResolver( SourceResolver { _, _ -> this.search.source } } else { SourceResolver { environment, sourceObject -> - val source = if (sourceObject != null) { - // if source object is known, environment is null as an optimization (LightDataFetcher) - sourceObject - } else { - environment - ?: throw ResolverError("Expected DataFetchingEnvironment to not be null!") - environment.getSource() - ?: throw ResolverError("Expected source object to not be null!") - } + // if source object is known, environment is null as an optimization (LightDataFetcher) + val source = sourceObject + ?: environment?.getSource() + ?: throw ResolverError("Expected DataFetchingEnvironment and source object to not be null!") if (!this.genericType.isAssignableFrom(source.javaClass)) { throw ResolverError("Expected source object to be an instance of '${this.genericType.getRawClass().name}' but instead got '${source.javaClass.name}'") diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/MapFieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/MapFieldResolver.kt index ce48e494..e2b635be 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/MapFieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/MapFieldResolver.kt @@ -52,7 +52,7 @@ internal class MapFieldResolver( internal class MapFieldResolverDataFetcher( private val sourceResolver: SourceResolver, - private val key: String, + private val key: String ) : LightDataFetcher { override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any?, environmentSupplier: Supplier): Any? { @@ -64,6 +64,6 @@ internal class MapFieldResolverDataFetcher( } override fun get(environment: DataFetchingEnvironment): Any? { - return get(environment.fieldDefinition, sourceResolver.resolve(environment, null), { environment }) + return get(environment.fieldDefinition, sourceResolver.resolve(environment, null)) { environment } } } diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt index a400b1e7..e7f6946d 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt @@ -31,7 +31,7 @@ internal class MethodFieldResolver( field: FieldDefinition, search: FieldResolverScanner.Search, options: SchemaParserOptions, - val method: Method, + val method: Method ) : FieldResolver(field, search, options, search.type) { private val log = LoggerFactory.getLogger(javaClass) @@ -202,10 +202,10 @@ internal class MethodFieldResolverDataFetcher( return if (isSuspendFunction) { environment.coroutineScope().future(options.coroutineContextProvider.provide()) { - invokeSuspend(source, method, args)?.transformWithGenericWrapper(options.genericWrappers, { environment }) + invokeSuspend(source, method, args)?.transformWithGenericWrapper(options.genericWrappers) { environment } } } else { - invoke(method, source, args)?.transformWithGenericWrapper(options.genericWrappers, { environment }) + invoke(method, source, args)?.transformWithGenericWrapper(options.genericWrappers) { environment } } } @@ -224,7 +224,7 @@ internal class MethodFieldResolverDataFetcher( internal class LightMethodFieldResolverDataFetcher( private val sourceResolver: SourceResolver, private val method: Method, - private val options: SchemaParserOptions, + private val options: SchemaParserOptions ) : LightDataFetcher { override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any?, environmentSupplier: Supplier): Any? { @@ -234,7 +234,7 @@ internal class LightMethodFieldResolverDataFetcher( } override fun get(environment: DataFetchingEnvironment): Any? { - return get(environment.fieldDefinition, sourceResolver.resolve(environment, null), { environment }) + return get(environment.fieldDefinition, sourceResolver.resolve(environment, null)) { environment } } /** @@ -249,7 +249,7 @@ internal class LightMethodFieldResolverDataFetcher( private fun Any.transformWithGenericWrapper( genericWrappers: List, environmentSupplier: Supplier -): Any? { +): Any { return genericWrappers .asSequence() .filter { it.type.isInstance(this) } diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/PropertyFieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/PropertyFieldResolver.kt index afbb29f3..6151181a 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/PropertyFieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/PropertyFieldResolver.kt @@ -18,7 +18,7 @@ internal class PropertyFieldResolver( field: FieldDefinition, search: FieldResolverScanner.Search, options: SchemaParserOptions, - private val property: Field, + private val property: Field ) : FieldResolver(field, search, options, property.declaringClass) { override fun createDataFetcher(): DataFetcher<*> { @@ -41,7 +41,7 @@ internal class PropertyFieldResolver( internal class PropertyFieldResolverDataFetcher( private val sourceResolver: SourceResolver, - private val field: Field, + private val field: Field ) : LightDataFetcher { override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any?, environmentSupplier: Supplier): Any? { @@ -49,6 +49,6 @@ internal class PropertyFieldResolverDataFetcher( } override fun get(environment: DataFetchingEnvironment): Any? { - return get(environment.fieldDefinition, sourceResolver.resolve(environment, null), { environment }) + return get(environment.fieldDefinition, sourceResolver.resolve(environment, null)) { environment } } } From e9074ec27b8a90f0e99793e4e2f910b723bc38a2 Mon Sep 17 00:00:00 2001 From: Oryan Date: Tue, 8 Oct 2024 10:20:47 -0400 Subject: [PATCH 09/12] Make nullable --- .../kickstart/tools/resolver/MethodFieldResolver.kt | 2 +- .../kickstart/tools/MethodFieldResolverDataFetcherTest.kt | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt index e7f6946d..76fc7f19 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt @@ -227,7 +227,7 @@ internal class LightMethodFieldResolverDataFetcher( private val options: SchemaParserOptions ) : LightDataFetcher { - override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any?, environmentSupplier: Supplier): Any? { + override fun get(fieldDefinition: GraphQLFieldDefinition?, sourceObject: Any?, environmentSupplier: Supplier): Any? { val source = sourceResolver.resolve(null, sourceObject) return invoke(method, source, emptyArray())?.transformWithGenericWrapper(options.genericWrappers, environmentSupplier) diff --git a/src/test/kotlin/graphql/kickstart/tools/MethodFieldResolverDataFetcherTest.kt b/src/test/kotlin/graphql/kickstart/tools/MethodFieldResolverDataFetcherTest.kt index 9401feef..481d2a4e 100644 --- a/src/test/kotlin/graphql/kickstart/tools/MethodFieldResolverDataFetcherTest.kt +++ b/src/test/kotlin/graphql/kickstart/tools/MethodFieldResolverDataFetcherTest.kt @@ -13,8 +13,6 @@ import graphql.language.TypeName import graphql.schema.DataFetcher import graphql.schema.DataFetchingEnvironment import graphql.schema.DataFetchingEnvironmentImpl -import graphql.schema.GraphQLFieldDefinition -import graphql.schema.GraphQLObjectType import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job @@ -301,12 +299,6 @@ class MethodFieldResolverDataFetcherTest { private fun createEnvironment(source: Any = Object(), arguments: Map = emptyMap(), context: GraphQLContext? = null): DataFetchingEnvironment { return DataFetchingEnvironmentImpl.newDataFetchingEnvironment(buildExecutionContext()) .source(source) - .fieldDefinition( - GraphQLFieldDefinition.newFieldDefinition() - .name("ignored") - .type(GraphQLObjectType.newObject().name("ignored").build()) - .build() - ) .arguments(arguments) .graphQLContext(context) .build() From d408078bcca217151d0bbb8478acee8532279109 Mon Sep 17 00:00:00 2001 From: Oryan Date: Tue, 8 Oct 2024 11:09:27 -0400 Subject: [PATCH 10/12] Add comment --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 2479b230..e9236fa1 100644 --- a/pom.xml +++ b/pom.xml @@ -307,6 +307,7 @@ **/*Test.* + --add-reads kotlin.stdlib=kotlinx.coroutines.core From fd06ad24924b03be3f90479158237613e1673696 Mon Sep 17 00:00:00 2001 From: Oryan Date: Tue, 8 Oct 2024 11:11:56 -0400 Subject: [PATCH 11/12] Revert version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e9236fa1..b5b67edc 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.graphql-java-kickstart graphql-java-tools - 14.2.0-LOCAL + 13.1.2-SNAPSHOT jar GraphQL Java Tools From 5a6dca0d26002267fb27a776b2f04d40d0453b90 Mon Sep 17 00:00:00 2001 From: Oryan Date: Tue, 8 Oct 2024 11:22:25 -0400 Subject: [PATCH 12/12] Remove argline --- pom.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pom.xml b/pom.xml index b5b67edc..8e1c131b 100644 --- a/pom.xml +++ b/pom.xml @@ -307,8 +307,6 @@ **/*Test.* - - --add-reads kotlin.stdlib=kotlinx.coroutines.core