Skip to content

fix unwrapGenericType to properly find generic type in arguments Map #361

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
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
14 changes: 11 additions & 3 deletions src/main/kotlin/graphql/kickstart/tools/GenericType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,17 @@ internal open class GenericType(protected val mostSpecificType: JavaType, protec
}
}

private fun unwrapGenericType(declaringType: ParameterizedType, type: TypeVariable<*>) =
unwrapGenericType(TypeUtils.determineTypeArguments(getRawClass(mostSpecificType), declaringType)[type]
?: error("No type variable found for: ${TypeUtils.toLongString(type)}"))
private fun unwrapGenericType(declaringType: ParameterizedType, type: TypeVariable<*>): JavaType {
val rawClass = getRawClass(mostSpecificType)
val arguments = TypeUtils.determineTypeArguments(rawClass, declaringType)
val matchingType = arguments
.filter { it.key.name == type.name }
.values
.firstOrNull()
?: error("No type variable found for: ${TypeUtils.toLongString(type)}")

return unwrapGenericType(matchingType)
}

private fun replaceTypeVariable(type: JavaType): JavaType {
return when (type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class SchemaParserSpec extends Specification {

def "builder doesn't throw FileNotFound exception when file is present"() {
when:
SchemaParser.newParser().file("test.graphqls")
SchemaParser.newParser().file("Test.graphqls")
.resolvers(new GraphQLQueryResolver() {
String getId() { "1" }
})
Expand Down Expand Up @@ -286,7 +286,7 @@ class SchemaParserSpec extends Specification {
def "parser should include source location for field definition when loaded from single classpath file"() {
when:
GraphQLSchema schema = SchemaParser.newParser()
.file("test.graphqls")
.file("Test.graphqls")
.resolvers(new QueryWithIdResolver())
.build()
.makeExecutableSchema()
Expand All @@ -298,7 +298,7 @@ class SchemaParserSpec extends Specification {
sourceLocation != null
sourceLocation.line == 2
sourceLocation.column == 5
sourceLocation.sourceName == "test.graphqls"
sourceLocation.sourceName == "Test.graphqls"
}

def "support enum types if only used as input type"() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package graphql.kickstart.tools

import graphql.ExecutionInput
import graphql.GraphQL
import org.junit.Test

class PlaceTest {

@Test
fun shouldHandleGenericsDeepHierarchy() {
val schema = SchemaParser.newParser()
.file("Place.graphqls")
.resolvers(PlaceQuery())
.build().makeExecutableSchema()

val graphql = GraphQL.newGraphQL(schema).build()
val query = "query { places1 { id } places2 { id } }"
val executionInput = ExecutionInput.newExecutionInput().query(query).build()
val result = graphql.execute(executionInput)

assert(result.getData<Map<String, List<*>>>()["places1"]?.size == 3)
assert(result.getData<Map<String, List<*>>>()["places2"]?.size == 2)
}
}

private class PlaceQuery : GraphQLQueryResolver {

fun places1(): List<Place1> = listOf(Place1("1"), Place1("2"), Place1("3"))

fun places2(): List<Place2> = listOf(Place2("4"), Place2("5"))
}

private abstract class Entity(val id: String? = null)

private abstract class OtherPlace<R : Review<*>>(id: String? = null) : Place<R>(id) {
val other: String? = null
}

private abstract class Place<R : Review<*>>(id: String? = null) : Entity(id) {
val name: String? = null
val reviews: MutableSet<R>? = null
}

private class Place1(id: String? = null) : OtherPlace<Review1>(id)

private class Place2(id: String? = null) : OtherPlace<Review2>(id)

private abstract class Review<T : Entity>(id: String? = null) : Entity(id) {
val rating: Int? = null
val content: T? = null
}

private class Review1(id: String? = null) : Review<Place1>(id)

private class Review2(id: String? = null) : Review<Place2>(id)
2 changes: 1 addition & 1 deletion src/test/kotlin/graphql/kickstart/tools/UtilsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class UtilsTest {
}

@Test
fun `isTrivialDataFetcher`() {
fun isTrivialDataFetcher() {
val clazz = Bean::class.java

Assert.assertTrue(isTrivialDataFetcher(clazz.getMethod("getterValid")))
Expand Down
51 changes: 51 additions & 0 deletions src/test/resources/Place.graphqls
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
type Query {
places1: [Place1!]
places2: [Place2!]
}

interface Entity {
id: ID!
}

interface Place {
name: String
reviews: [Review!]
}

interface OtherPlace {
name: String
other: String
reviews: [Review!]
}

type Place1 implements Entity, Place, OtherPlace {
id: ID!
name: String
other: String
reviews: [Review1!]
}

type Place2 implements Entity, Place, OtherPlace {
id: ID!
name: String
other: String
reviews: [Review2!]
}

interface Review {
id: ID!
rating: Int
content: Entity
}

type Review1 implements Review {
id: ID!
rating: Int
content: Place1
}

type Review2 implements Review {
id: ID!
rating: Int
content: Place2
}
File renamed without changes.