Skip to content

Commit 24b42b0

Browse files
authored
Merge pull request #185 from graphql-java-kickstart/bugfix/114
Bugfix/114
2 parents 18eec21 + 48b3177 commit 24b42b0

18 files changed

+299
-170
lines changed

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ language: java
22
jdk:
33
- oraclejdk8
44
sudo: false
5-
script: mvn clean verify
5+
script:
6+
- sh travis-build.sh

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# GraphQL Java Tools
22

3-
[![TravisCI Build](https://travis-ci.org/graphql-java/graphql-java-tools.svg?branch=master)](https://travis-ci.org/graphql-java/graphql-java-tools)
3+
[![TravisCI Build](https://travis-ci.org/graphql-java-kickstart/graphql-java-tools.svg?branch=master)](https://travis-ci.org/graphql-java-kickstart/graphql-java-tools)
44
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.graphql-java/graphql-java-tools/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.graphql-java/graphql-java-tools)
55
[![Chat on Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/graphql-java/graphql-java)
66

pom.xml

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
33
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
44
<modelVersion>4.0.0</modelVersion>
55

6-
<groupId>com.graphql-java</groupId>
6+
<groupId>com.graphql-java-kickstart</groupId>
77
<artifactId>graphql-java-tools</artifactId>
8-
<version>5.2.5-SNAPSHOT</version>
8+
<version>5.3.0-SNAPSHOT</version>
99
<packaging>jar</packaging>
1010

1111
<name>GraphQL Java Tools</name>
@@ -15,7 +15,7 @@
1515
<properties>
1616
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1717
<java.version>1.8</java.version>
18-
<kotlin.version>1.2.60</kotlin.version>
18+
<kotlin.version>1.2.71</kotlin.version>
1919
<jackson.version>2.9.6</jackson.version>
2020

2121
<!--This contends with dokka and creates two javadoc jars...-->
@@ -212,19 +212,6 @@
212212
</execution>
213213
</executions>
214214
</plugin>
215-
<plugin>
216-
<groupId>org.jetbrains.dokka</groupId>
217-
<artifactId>dokka-maven-plugin</artifactId>
218-
<version>0.9.14</version>
219-
<executions>
220-
<execution>
221-
<phase>package</phase>
222-
<goals>
223-
<goal>javadocJar</goal>
224-
</goals>
225-
</execution>
226-
</executions>
227-
</plugin>
228215
</plugins>
229216
</build>
230217
</profile>
@@ -247,19 +234,21 @@
247234
<distributionManagement>
248235
<snapshotRepository>
249236
<id>bintray</id>
250-
<url>https://api.bintray.com/maven/apottere/maven/graphql-java-tools</url>
237+
<name>graphql-java-kickstart-graphql-java-tools</name>
238+
<url>https://api.bintray.com/maven/graphql-java-kickstart/graphql-java-tools/graphql-java-tools/</url>
251239
</snapshotRepository>
252240

253241
<!-- Released with: mvn release:clean release:prepare release:perform -B -e -Pbintray -->
254242
<repository>
255243
<id>bintray</id>
256-
<url>https://api.bintray.com/maven/apottere/maven/graphql-java-tools/;publish=1</url>
244+
<name>graphql-java-kickstart-graphql-java-tools</name>
245+
<url>https://api.bintray.com/maven/graphql-java-kickstart/graphql-java-tools/graphql-java-tools/;publish=1</url>
257246
</repository>
258247
</distributionManagement>
259248
<scm>
260-
<connection>scm:git:git://github.com/graphql-java/graphql-java-tools.git</connection>
261-
<developerConnection>scm:git:git@github.com:graphql-java/graphql-java-tools.git</developerConnection>
262-
<url>http://github.com/graphql-java/graphql-java-tools</url>
249+
<connection>scm:git:git://github.com/graphql-java-kickstart/graphql-java-tools.git</connection>
250+
<developerConnection>scm:git:git@github.com:graphql-java-kickstart/graphql-java-tools.git</developerConnection>
251+
<url>http://github.com/graphql-javakickstart/graphql-java-tools</url>
263252
<tag>HEAD</tag>
264253
</scm>
265254
</project>

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import graphql.schema.TypeResolver
1111
/**
1212
* @author Andrew Potter
1313
*/
14-
abstract class DictionaryTypeResolver(private val dictionary: BiMap<Class<*>, TypeDefinition<*>>, private val types: Map<String, GraphQLObjectType>) : TypeResolver {
14+
abstract class DictionaryTypeResolver(private val dictionary: BiMap<JavaType, TypeDefinition<*>>, private val types: Map<String, GraphQLObjectType>) : TypeResolver {
1515
private fun <T> getTypeName(clazz: Class<T>): String? {
1616
val name = dictionary[clazz]?.name
1717

@@ -34,11 +34,11 @@ abstract class DictionaryTypeResolver(private val dictionary: BiMap<Class<*>, Ty
3434
abstract fun getError(name: String): String
3535
}
3636

37-
class InterfaceTypeResolver(dictionary: BiMap<Class<*>, TypeDefinition<*>>, private val thisInterface: GraphQLInterfaceType, types: List<GraphQLObjectType>) : DictionaryTypeResolver(dictionary, types.filter { it.interfaces.any { it.name == thisInterface.name } }.associateBy { it.name }) {
37+
class InterfaceTypeResolver(dictionary: BiMap<JavaType, TypeDefinition<*>>, private val thisInterface: GraphQLInterfaceType, types: List<GraphQLObjectType>) : DictionaryTypeResolver(dictionary, types.filter { it.interfaces.any { it.name == thisInterface.name } }.associateBy { it.name }) {
3838
override fun getError(name: String) = "Expected object type with name '$name' to implement interface '${thisInterface.name}', but it doesn't!"
3939
}
4040

41-
class UnionTypeResolver(dictionary: BiMap<Class<*>, TypeDefinition<*>>, private val thisUnion: GraphQLUnionType, types: List<GraphQLObjectType>) : DictionaryTypeResolver(dictionary, types.filter { type -> thisUnion.types.any { it.name == type.name } }.associateBy { it.name }) {
41+
class UnionTypeResolver(dictionary: BiMap<JavaType, TypeDefinition<*>>, private val thisUnion: GraphQLUnionType, types: List<GraphQLObjectType>) : DictionaryTypeResolver(dictionary, types.filter { type -> thisUnion.types.any { it.name == type.name } }.associateBy { it.name }) {
4242
override fun getError(name: String) = "Expected object type with name '$name' to exist for union '${thisUnion.name}', but it doesn't!"
4343
}
4444

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) {
2020
companion object {
2121
private val log = LoggerFactory.getLogger(FieldResolverScanner::class.java)
2222

23-
fun getAllMethods(type: Class<*>) =
24-
(type.declaredMethods.toList() + ClassUtils.getAllSuperclasses(type).flatMap { it.methods.toList() })
23+
fun getAllMethods(type: JavaType) =
24+
(type.unwrap().declaredMethods.toList() + ClassUtils.getAllSuperclasses(type.unwrap()).flatMap { it.methods.toList() })
2525
.asSequence()
2626
.filter { !it.isSynthetic }
2727
.filter { !Modifier.isPrivate(it.modifiers) }
@@ -131,7 +131,7 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) {
131131
}
132132

133133
private fun findResolverProperty(field: FieldDefinition, search: Search) =
134-
FieldUtils.getAllFields(search.type).find { it.name == field.name }
134+
FieldUtils.getAllFields(search.type.unwrap()).find { it.name == field.name }
135135

136136
private fun getMissingFieldMessage(field: FieldDefinition, searches: List<Search>, scannedProperties: Boolean): String {
137137
val signatures = mutableListOf("")
@@ -143,11 +143,11 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) {
143143

144144
val sourceName = if (field.sourceLocation != null && field.sourceLocation.sourceName != null) field.sourceLocation.sourceName else "<unknown>"
145145
val sourceLocation = if (field.sourceLocation != null) "$sourceName:${field.sourceLocation.line}" else "<unknown>"
146-
return "No method${if (scannedProperties) " or field" else ""} found as defined in $sourceLocation with any of the following signatures (with or without one of $allowedLastArgumentTypes as the last argument), in priority order:\n${signatures.joinToString("\n ")}"
146+
return "No method${if (scannedProperties) " or field" else ""} found as defined in schema $sourceLocation with any of the following signatures (with or without one of $allowedLastArgumentTypes as the last argument), in priority order:\n${signatures.joinToString("\n ")}"
147147
}
148148

149149
private fun getMissingMethodSignatures(field: FieldDefinition, search: Search, isBoolean: Boolean, scannedProperties: Boolean): List<String> {
150-
val baseType = search.type
150+
val baseType = search.type.unwrap()
151151
val signatures = mutableListOf<String>()
152152
val args = mutableListOf<String>()
153153
val sep = ", "
@@ -172,7 +172,7 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) {
172172
return signatures
173173
}
174174

175-
data class Search(val type: Class<*>, val resolverInfo: ResolverInfo, val source: Any?, val requiredFirstParameterType: Class<*>? = null, val allowBatched: Boolean = false)
175+
data class Search(val type: JavaType, val resolverInfo: ResolverInfo, val source: Any?, val requiredFirstParameterType: Class<*>? = null, val allowBatched: Boolean = false)
176176
}
177177

178178
class FieldResolverError(msg: String) : RuntimeException(msg)

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

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@ package com.coxautodev.graphql.tools
22

33
import com.google.common.primitives.Primitives
44
import org.apache.commons.lang3.reflect.TypeUtils
5+
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
56
import sun.reflect.generics.reflectiveObjects.WildcardTypeImpl
67
import java.lang.reflect.ParameterizedType
78
import java.lang.reflect.TypeVariable
89

910
/**
1011
* @author Andrew Potter
1112
*/
12-
open internal class GenericType(protected val mostSpecificType: JavaType, protected val options: SchemaParserOptions) {
13+
internal open class GenericType(protected val mostSpecificType: JavaType, protected val options: SchemaParserOptions) {
1314

1415
fun isTypeAssignableFromRawClass(type: ParameterizedType, clazz: Class<*>) =
15-
clazz.isAssignableFrom(getRawClass(type.rawType))
16+
clazz.isAssignableFrom(getRawClass(type.rawType))
1617

1718
fun getRawClass() = getRawClass(mostSpecificType)
1819

@@ -21,29 +22,30 @@ open internal class GenericType(protected val mostSpecificType: JavaType, protec
2122
fun isAssignableFrom(type: JavaType) = TypeUtils.isAssignable(type, mostSpecificType)
2223

2324
fun relativeToPotentialParent(declaringType: JavaType): RelativeTo {
24-
if(declaringType !is Class<*>) {
25+
if (declaringType !is Class<*> || declaringType.isInterface) {
2526
return relativeToType(declaringType)
2627
}
2728

2829
val type = getGenericSuperType(mostSpecificType, declaringType)
29-
if(type == null) {
30+
if (type == null) {
3031
error("Unable to find generic type of class ${TypeUtils.toString(declaringType)} relative to ${TypeUtils.toString(mostSpecificType)}")
3132
} else {
3233
return relativeToType(type)
3334
}
3435
}
36+
3537
fun relativeToType(declaringType: JavaType) = RelativeTo(declaringType, mostSpecificType, options)
3638

3739
fun getGenericInterface(targetInterface: Class<*>) = getGenericInterface(mostSpecificType, targetInterface)
3840

3941
private fun getGenericInterface(type: JavaType?, targetInterface: Class<*>): JavaType? {
40-
if(type == null) {
42+
if (type == null) {
4143
return null
4244
}
4345

4446
val raw = type as? Class<*> ?: getRawClass(type)
4547

46-
if(raw == targetInterface) {
48+
if (raw == targetInterface) {
4749
return type
4850
}
4951

@@ -59,54 +61,88 @@ open internal class GenericType(protected val mostSpecificType: JavaType, protec
5961
fun getGenericSuperType(targetSuperClass: Class<*>) = getGenericSuperType(mostSpecificType, targetSuperClass)
6062

6163
private fun getGenericSuperType(type: JavaType?, targetSuperClass: Class<*>): JavaType? {
62-
if(type == null) {
64+
if (type == null) {
6365
return null
6466
}
6567

6668
val raw = type as? Class<*> ?: TypeUtils.getRawType(type, type)
6769

68-
if(raw == targetSuperClass) {
70+
if (raw == targetSuperClass) {
6971
return type
7072
}
7173

7274
return getGenericSuperType(raw.genericSuperclass, targetSuperClass)
7375
}
7476

75-
class RelativeTo(private val declaringType: JavaType, mostSpecificType: JavaType, options: SchemaParserOptions): GenericType(mostSpecificType, options) {
77+
class RelativeTo(private val declaringType: JavaType, mostSpecificType: JavaType, options: SchemaParserOptions) : GenericType(mostSpecificType, options) {
7678

7779
/**
7880
* Unwrap certain Java types to find the "real" class.
7981
*/
80-
fun unwrapGenericType(type: JavaType): JavaType {
81-
return when(type) {
82+
fun unwrapGenericType(javaType: JavaType): JavaType {
83+
val type = replaceTypeVariable(javaType)
84+
return when (type) {
8285
is ParameterizedType -> {
8386
val rawType = type.rawType
8487
val genericType = options.genericWrappers.find { it.type == rawType } ?: return type
8588

8689
val typeArguments = type.actualTypeArguments
87-
if(typeArguments.size <= genericType.index) {
90+
if (typeArguments.size <= genericType.index) {
8891
throw IndexOutOfBoundsException("Generic type '${TypeUtils.toString(type)}' does not have a type argument at index ${genericType.index}!")
8992
}
9093

91-
val unwrapsTo = if (genericType.schemaWrapper != null) {
92-
genericType.schemaWrapper.invoke(typeArguments[genericType.index])
93-
} else {
94-
typeArguments[genericType.index]
95-
}
96-
94+
val unwrapsTo = genericType.schemaWrapper.invoke(typeArguments[genericType.index])
9795
return unwrapGenericType(unwrapsTo)
9896
}
99-
is Class<*> -> if(type.isPrimitive) Primitives.wrap(type) else type
10097
is TypeVariable<*> -> {
101-
if(declaringType !is ParameterizedType) {
98+
val parameterizedDeclaringType = parameterizedDeclaringTypeOrSuperType(declaringType)
99+
if (parameterizedDeclaringType != null) {
100+
unwrapGenericType(parameterizedDeclaringType, type)
101+
} else {
102102
error("Could not resolve type variable '${TypeUtils.toLongString(type)}' because declaring type is not parameterized: ${TypeUtils.toString(declaringType)}")
103103
}
104-
105-
unwrapGenericType(TypeUtils.determineTypeArguments(getRawClass(mostSpecificType), declaringType)[type] ?: error("No type variable found for: ${TypeUtils.toLongString(type)}"))
106104
}
107-
is WildcardTypeImpl -> type.upperBounds.firstOrNull() ?: throw error("Unable to unwrap type, wildcard has no upper bound: $type")
105+
is WildcardTypeImpl -> type.upperBounds.firstOrNull()
106+
?: throw error("Unable to unwrap type, wildcard has no upper bound: $type")
107+
is Class<*> -> if (type.isPrimitive) Primitives.wrap(type) else type
108108
else -> error("Unable to unwrap type: $type")
109109
}
110110
}
111+
112+
private fun parameterizedDeclaringTypeOrSuperType(declaringType: JavaType): ParameterizedType? =
113+
if (declaringType is ParameterizedType) {
114+
declaringType
115+
} else {
116+
val superclass = declaringType.unwrap().genericSuperclass
117+
if (superclass != null) {
118+
parameterizedDeclaringTypeOrSuperType(superclass)
119+
} else {
120+
null
121+
}
122+
}
123+
124+
private fun unwrapGenericType(declaringType: ParameterizedType, type: TypeVariable<*>) =
125+
unwrapGenericType(TypeUtils.determineTypeArguments(getRawClass(mostSpecificType), declaringType)[type]
126+
?: error("No type variable found for: ${TypeUtils.toLongString(type)}"))
127+
128+
private fun replaceTypeVariable(type: JavaType): JavaType {
129+
return when (type) {
130+
is ParameterizedType -> {
131+
val actualTypeArguments = type.actualTypeArguments.map { replaceTypeVariable(it) }.toTypedArray()
132+
ParameterizedTypeImpl.make(type.rawType as Class<*>?, actualTypeArguments, type.ownerType)
133+
}
134+
is TypeVariable<*> -> {
135+
if (declaringType is ParameterizedType) {
136+
TypeUtils.getRawType(type, declaringType)
137+
} else {
138+
type
139+
}
140+
}
141+
else -> {
142+
type
143+
}
144+
}
145+
}
146+
111147
}
112148
}

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,24 @@ import graphql.language.NonNullType
99
import graphql.schema.DataFetcher
1010
import graphql.schema.DataFetchingEnvironment
1111
import java.lang.reflect.Method
12+
import java.lang.reflect.ParameterizedType
13+
import java.lang.reflect.TypeVariable
1214
import java.util.*
1315

1416
/**
1517
* @author Andrew Potter
1618
*/
17-
internal class MethodFieldResolver(field: FieldDefinition, search: FieldResolverScanner.Search, options: SchemaParserOptions, val method: Method) : FieldResolver(field, search, options, method.declaringClass) {
19+
internal class MethodFieldResolver(field: FieldDefinition, search: FieldResolverScanner.Search, options: SchemaParserOptions, val method: Method) : FieldResolver(field, search, options, search.type) {
1820

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

2628
return true
2729
}
28-
2930
return false
3031
}
3132
}
@@ -98,7 +99,8 @@ internal class MethodFieldResolver(field: FieldDefinition, search: FieldResolver
9899

99100
override fun scanForMatches(): List<TypeClassMatcher.PotentialMatch> {
100101
val batched = isBatched(method, search)
101-
val returnValueMatch = TypeClassMatcher.PotentialMatch.returnValue(field.type, method.genericReturnType, genericType, SchemaClassScanner.ReturnValueReference(method), batched)
102+
val unwrappedGenericType = genericType.unwrapGenericType(method.genericReturnType)
103+
val returnValueMatch = TypeClassMatcher.PotentialMatch.returnValue(field.type, unwrappedGenericType, genericType, SchemaClassScanner.ReturnValueReference(method), batched)
102104

103105
return field.inputValueDefinitions.mapIndexed { i, inputDefinition ->
104106
TypeClassMatcher.PotentialMatch.parameterType(inputDefinition.type, getJavaMethodParameterType(i)!!, genericType, SchemaClassScanner.MethodParameterReference(method, i), batched)

0 commit comments

Comments
 (0)