Skip to content

Commit 2a5940e

Browse files
In a stituation where there is a type conflict and you have an explicit resolver, add option to prefer the resolver
1 parent 87cefed commit 2a5940e

File tree

3 files changed

+38
-4
lines changed

3 files changed

+38
-4
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,3 +335,19 @@ Options:
335335
* `useDefaultGenericWrappers`: Defaults to `true`. Tells the parser whether or not to add it's own list of well-known generic wrappers, such as `Future` and `CompletableFuture`.
336336
* `allowUnimplementedResolvers`: Defaults to `false`. Allows a schema to be created even if not all GraphQL fields have resolvers. Intended only for development, it will log a warning to remind you to turn it off for production. Any unimplemented resolvers will throw errors when queried.
337337
* `objectMapperConfigurer`: Exposes the Jackson `ObjectMapper` that handles marshalling arguments in method resolvers. Every method resolver gets its own mapper, and the configurer can configure it differently based on the GraphQL field definition.
338+
* `preferGraphQLResolver`: In cases where you have a Resolver class and legacy class that conflict on type arguements, use the Resolver class instead of throwing an error.
339+
340+
Specificly this situation can occur when you have a graphql schema type `Foo` with a `bars` property and classes:
341+
```java
342+
// legacy class you can't change
343+
class Foo {
344+
Set<Bar> getBars() {...returns set of bars...}
345+
}
346+
347+
// nice resolver that does what you want
348+
class FooResolver implements GraphQLResolver<Foo> {
349+
Set<BarDTO> getBars() {...converts Bar objects to BarDTO objects and retunrs set...}
350+
}
351+
```
352+
You will now have the code find two different return types for getBars() and application will not start with the error ```Caused by: com.coxautodev.graphql.tools.SchemaClassScannerError: Two different classes used for type```
353+
If this property is true it will ignore the legacy version.

src/main/kotlin/com/coxautodev/graphql/tools/SchemaClassScanner.kt

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,11 @@ internal class SchemaClassScanner(initialDictionary: BiMap<String, Class<*>>, al
260260
typeWasSet = realEntry.setTypeIfMissing(clazz)
261261

262262
if (realEntry.typeClass != clazz) {
263-
throw SchemaClassScannerError("Two different classes used for type ${type.name}:\n${realEntry.joinReferences()}\n\n- $clazz:\n| ${reference.getDescription()}")
263+
if (options.preferGraphQLResolver && realEntry.hasResolverRef()) {
264+
log.warn("The real entry ${realEntry.joinReferences()} is a GraphQLResolver so ignoring this one $clazz $reference")
265+
} else {
266+
throw SchemaClassScannerError("Two different classes used for type ${type.name}:\n${realEntry.joinReferences()}\n\n- $clazz:\n| ${reference.getDescription()}")
267+
}
264268
}
265269
}
266270

@@ -346,8 +350,16 @@ internal class SchemaClassScanner(initialDictionary: BiMap<String, Class<*>>, al
346350
fun addReference(reference: Reference) {
347351
references.add(reference)
348352
}
349-
350353
fun joinReferences() = "- $typeClass:\n| " + references.joinToString("\n| ") { it.getDescription() }
354+
355+
fun hasResolverRef():Boolean {
356+
references.filterIsInstance<ReturnValueReference>().forEach{ reference ->
357+
if (GraphQLResolver::class.java.isAssignableFrom(reference.getMethod().declaringClass)) {
358+
return true
359+
}
360+
}
361+
return false
362+
}
351363
}
352364

353365
abstract class Reference {
@@ -378,6 +390,7 @@ internal class SchemaClassScanner(initialDictionary: BiMap<String, Class<*>>, al
378390
}
379391

380392
class ReturnValueReference(private val method: Method): Reference() {
393+
fun getMethod () = method;
381394
override fun getDescription() = "return type of method $method"
382395
}
383396

src/main/kotlin/com/coxautodev/graphql/tools/SchemaParserBuilder.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ class SchemaParserDictionary {
225225
}
226226
}
227227

228-
data class SchemaParserOptions internal constructor(val contextClass: Class<*>?, val genericWrappers: List<GenericWrapper>, val allowUnimplementedResolvers: Boolean, val objectMapperProvider: PerFieldObjectMapperProvider, val proxyHandlers: List<ProxyHandler>) {
228+
data class SchemaParserOptions internal constructor(val contextClass: Class<*>?, val genericWrappers: List<GenericWrapper>, val allowUnimplementedResolvers: Boolean, val objectMapperProvider: PerFieldObjectMapperProvider, val proxyHandlers: List<ProxyHandler>, val preferGraphQLResolver: Boolean) {
229229
companion object {
230230
@JvmStatic fun newOptions() = Builder()
231231
@JvmStatic fun defaultOptions() = Builder().build()
@@ -238,6 +238,7 @@ data class SchemaParserOptions internal constructor(val contextClass: Class<*>?,
238238
private var allowUnimplementedResolvers = false
239239
private var objectMapperProvider: PerFieldObjectMapperProvider = PerFieldConfiguringObjectMapperProvider()
240240
private val proxyHandlers: MutableList<ProxyHandler> = mutableListOf(Spring4AopProxyHandler(), GuiceAopProxyHandler(), JavassistProxyHandler())
241+
private var preferGraphQLResolver = false
241242

242243
fun contextClass(contextClass: Class<*>) = this.apply {
243244
this.contextClass = contextClass
@@ -263,6 +264,10 @@ data class SchemaParserOptions internal constructor(val contextClass: Class<*>?,
263264
this.allowUnimplementedResolvers = allowUnimplementedResolvers
264265
}
265266

267+
fun preferGraphQLResolver(preferGraphQLResolver: Boolean) = this.apply {
268+
this.preferGraphQLResolver = preferGraphQLResolver
269+
}
270+
266271
fun objectMapperConfigurer(objectMapperConfigurer: ObjectMapperConfigurer) = this.apply {
267272
this.objectMapperProvider = PerFieldConfiguringObjectMapperProvider(objectMapperConfigurer)
268273
}
@@ -290,7 +295,7 @@ data class SchemaParserOptions internal constructor(val contextClass: Class<*>?,
290295
genericWrappers
291296
}
292297

293-
return SchemaParserOptions(contextClass, wrappers, allowUnimplementedResolvers, objectMapperProvider, proxyHandlers)
298+
return SchemaParserOptions(contextClass, wrappers, allowUnimplementedResolvers, objectMapperProvider, proxyHandlers, preferGraphQLResolver)
294299
}
295300
}
296301

0 commit comments

Comments
 (0)