Skip to content

Commit 3497692

Browse files
authored
Backport GraphQLUnion to 4.x.x (ExpediaGroup#1234)
1 parent edad0b4 commit 3497692

File tree

16 files changed

+368
-51
lines changed

16 files changed

+368
-51
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2021 Expedia, Inc
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.expediagroup.graphql.generator.annotations
18+
19+
import kotlin.reflect.KClass
20+
21+
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION)
22+
annotation class GraphQLUnion(
23+
val name: String,
24+
val possibleTypes: Array<KClass<*>>,
25+
val description: String = ""
26+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2021 Expedia, Inc
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.expediagroup.graphql.generator.exceptions
18+
19+
import kotlin.reflect.KType
20+
21+
class InvalidCustomUnionException(returnType: KType) :
22+
GraphQLKotlinException("The custom union annotation was used but the return type was $returnType instead of Any")

generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/internal/extensions/annotationExtensions.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package com.expediagroup.graphql.generator.internal.extensions
1919
import com.expediagroup.graphql.generator.annotations.GraphQLDescription
2020
import com.expediagroup.graphql.generator.annotations.GraphQLIgnore
2121
import com.expediagroup.graphql.generator.annotations.GraphQLName
22+
import com.expediagroup.graphql.generator.annotations.GraphQLUnion
2223
import kotlin.reflect.KAnnotatedElement
2324
import kotlin.reflect.full.findAnnotation
2425

@@ -30,7 +31,9 @@ internal fun KAnnotatedElement.getDeprecationReason(): String? = this.findAnnota
3031

3132
internal fun KAnnotatedElement.isGraphQLIgnored(): Boolean = this.findAnnotation<GraphQLIgnore>() != null
3233

33-
internal fun Deprecated.getReason(): String? {
34+
internal fun List<Annotation>.getUnionAnnotation(): GraphQLUnion? = this.filterIsInstance(GraphQLUnion::class.java).firstOrNull()
35+
36+
internal fun Deprecated.getReason(): String {
3437
val builder = StringBuilder()
3538
builder.append(this.message)
3639

generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/internal/extensions/kClassExtensions.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,11 @@ internal fun KClass<*>.findConstructorParameter(name: String): KParameter? =
6060
internal fun KClass<*>.isInterface(): Boolean =
6161
this.java.isInterface || this.isAbstract || this.isSealed
6262

63-
internal fun KClass<*>.isUnion(): Boolean =
64-
this.isInterface() && this.declaredMemberProperties.isEmpty() && this.declaredMemberFunctions.isEmpty()
63+
internal fun KClass<*>.isUnion(fieldAnnotations: List<Annotation> = emptyList()): Boolean = this.isDeclaredUnion() || this.isAnnotationUnion(fieldAnnotations)
64+
65+
private fun KClass<*>.isDeclaredUnion() = this.isInterface() && this.declaredMemberProperties.isEmpty() && this.declaredMemberFunctions.isEmpty()
66+
67+
internal fun KClass<*>.isAnnotationUnion(fieldAnnotations: List<Annotation>): Boolean = this.isInstance(Any::class) && fieldAnnotations.getUnionAnnotation() != null
6568

6669
/**
6770
* Do not add interfaces as additional types if it expects all the types

generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/internal/state/TypesCache.kt

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,14 @@
1616

1717
package com.expediagroup.graphql.generator.internal.state
1818

19+
import com.expediagroup.graphql.generator.annotations.GraphQLUnion
1920
import com.expediagroup.graphql.generator.exceptions.ConflictingTypesException
21+
import com.expediagroup.graphql.generator.exceptions.InvalidCustomUnionException
2022
import com.expediagroup.graphql.generator.exceptions.TypeNotSupportedException
2123
import com.expediagroup.graphql.generator.internal.extensions.getKClass
2224
import com.expediagroup.graphql.generator.internal.extensions.getSimpleName
25+
import com.expediagroup.graphql.generator.internal.extensions.getUnionAnnotation
26+
import com.expediagroup.graphql.generator.internal.extensions.isAnnotationUnion
2327
import com.expediagroup.graphql.generator.internal.extensions.isListType
2428
import com.expediagroup.graphql.generator.internal.extensions.qualifiedName
2529
import graphql.schema.GraphQLNamedType
@@ -36,6 +40,11 @@ internal class TypesCache(private val supportedPackages: List<String>) : Closeab
3640
private val cache: MutableMap<String, KGraphQLType> = mutableMapOf()
3741
private val typesUnderConstruction: MutableSet<TypesCacheKey> = mutableSetOf()
3842

43+
internal fun get(type: KType, inputType: Boolean, annotations: List<Annotation>): GraphQLNamedType? {
44+
val cacheKey = generateCacheKey(type, inputType, annotations)
45+
return get(cacheKey)
46+
}
47+
3948
@Throws(ConflictingTypesException::class)
4049
internal fun get(cacheKey: TypesCacheKey): GraphQLNamedType? {
4150
val cacheKeyString = getCacheKeyString(cacheKey) ?: return null
@@ -64,6 +73,28 @@ internal class TypesCache(private val supportedPackages: List<String>) : Closeab
6473
return null
6574
}
6675

76+
private fun generateCacheKey(type: KType, inputType: Boolean, annotations: List<Annotation> = emptyList()): TypesCacheKey {
77+
if (type.getKClass().isListType()) {
78+
return TypesCacheKey(type, inputType)
79+
}
80+
81+
val unionAnnotation = annotations.getUnionAnnotation()
82+
83+
return if (unionAnnotation != null) {
84+
if (type.getKClass().isAnnotationUnion(annotations)) {
85+
TypesCacheKey(type = type, inputType = inputType, name = getCustomUnionNameKey(unionAnnotation))
86+
} else {
87+
throw InvalidCustomUnionException(type)
88+
}
89+
} else {
90+
TypesCacheKey(type = type, inputType = inputType)
91+
}
92+
}
93+
94+
private fun getCustomUnionNameKey(union: GraphQLUnion): String {
95+
return union.name + union.possibleTypes.joinToString(prefix = "[", postfix = "]", separator = ",") { it.getSimpleName() }
96+
}
97+
6798
/**
6899
* Clear the cache of all saved values
69100
*/
@@ -80,25 +111,29 @@ internal class TypesCache(private val supportedPackages: List<String>) : Closeab
80111
* Enums do not have a different name for input and output.
81112
*/
82113
private fun getCacheKeyString(cacheKey: TypesCacheKey): String? {
83-
val type = cacheKey.type
84-
val kClass = type.getKClass()
114+
return if (cacheKey.name != null) {
115+
cacheKey.name
116+
} else {
117+
val type = cacheKey.type
118+
val kClass = type.getKClass()
85119

86-
return when {
87-
kClass.isListType() -> null
88-
kClass.isSubclassOf(Enum::class) -> kClass.getSimpleName()
89-
isTypeNotSupported(type) -> throw TypeNotSupportedException(type, supportedPackages)
90-
else -> type.getSimpleName(cacheKey.inputType)
120+
when {
121+
kClass.isListType() -> null
122+
kClass.isSubclassOf(Enum::class) -> kClass.getSimpleName()
123+
isTypeNotSupported(type) -> throw TypeNotSupportedException(type, supportedPackages)
124+
else -> type.getSimpleName(cacheKey.inputType)
125+
}
91126
}
92127
}
93128

94129
private fun isTypeNotSupported(type: KType): Boolean = supportedPackages.none { type.qualifiedName.startsWith(it) }
95130

96-
internal fun buildIfNotUnderConstruction(kClass: KClass<*>, inputType: Boolean, build: (KClass<*>) -> GraphQLType): GraphQLType {
131+
internal fun buildIfNotUnderConstruction(kClass: KClass<*>, inputType: Boolean, annotations: List<Annotation>, build: (KClass<*>) -> GraphQLType): GraphQLType {
97132
if (kClass.isListType()) {
98133
return build(kClass)
99134
}
100135

101-
val cacheKey = TypesCacheKey(kClass.starProjectedType, inputType)
136+
val cacheKey = generateCacheKey(kClass.starProjectedType, inputType, annotations)
102137
val cachedType = get(cacheKey)
103138
return when {
104139
cachedType != null -> cachedType

generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/internal/state/TypesCacheKey.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,8 @@ package com.expediagroup.graphql.generator.internal.state
1818

1919
import kotlin.reflect.KType
2020

21-
internal data class TypesCacheKey(val type: KType, val inputType: Boolean)
21+
internal data class TypesCacheKey(
22+
val type: KType,
23+
val inputType: Boolean = false,
24+
val name: String? = null
25+
)

generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/internal/types/generateFunction.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ internal fun generateFunction(generator: SchemaGenerator, fn: KFunction<*>, pare
5151

5252
val typeFromHooks = generator.config.hooks.willResolveMonad(fn.returnType)
5353
val returnType = getWrappedReturnType(typeFromHooks)
54-
val graphQLOutputType = generateGraphQLType(generator = generator, type = returnType).safeCast<GraphQLOutputType>()
54+
val graphQLOutputType = generateGraphQLType(generator = generator, type = returnType, annotations = fn.annotations).safeCast<GraphQLOutputType>()
5555
val graphQLType = builder.type(graphQLOutputType).build()
5656
val coordinates = FieldCoordinates.coordinates(parentName, functionName)
5757

generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/internal/types/generateGraphQLType.kt

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ package com.expediagroup.graphql.generator.internal.types
1919
import com.expediagroup.graphql.generator.SchemaGenerator
2020
import com.expediagroup.graphql.generator.extensions.unwrapType
2121
import com.expediagroup.graphql.generator.internal.extensions.getKClass
22+
import com.expediagroup.graphql.generator.internal.extensions.getUnionAnnotation
2223
import com.expediagroup.graphql.generator.internal.extensions.isEnum
2324
import com.expediagroup.graphql.generator.internal.extensions.isInterface
2425
import com.expediagroup.graphql.generator.internal.extensions.isListType
2526
import com.expediagroup.graphql.generator.internal.extensions.isUnion
2627
import com.expediagroup.graphql.generator.internal.extensions.wrapInNonNull
27-
import com.expediagroup.graphql.generator.internal.state.TypesCacheKey
2828
import graphql.schema.GraphQLType
2929
import graphql.schema.GraphQLTypeReference
3030
import kotlin.reflect.KClass
@@ -33,11 +33,11 @@ import kotlin.reflect.KType
3333
/**
3434
* Return a basic GraphQL type given all the information about the kotlin type.
3535
*/
36-
internal fun generateGraphQLType(generator: SchemaGenerator, type: KType, inputType: Boolean = false): GraphQLType {
36+
internal fun generateGraphQLType(generator: SchemaGenerator, type: KType, inputType: Boolean = false, annotations: List<Annotation> = emptyList()): GraphQLType {
3737
val hookGraphQLType = generator.config.hooks.willGenerateGraphQLType(type)
3838
val graphQLType = hookGraphQLType
3939
?: generateScalar(generator, type)
40-
?: objectFromReflection(generator, type, inputType)
40+
?: objectFromReflection(generator, type, inputType, annotations)
4141

4242
// Do not call the hook on GraphQLTypeReference as we have not generated the type yet
4343
val unwrappedType = graphQLType.unwrapType()
@@ -49,26 +49,25 @@ internal fun generateGraphQLType(generator: SchemaGenerator, type: KType, inputT
4949
return typeWithNullability
5050
}
5151

52-
private fun objectFromReflection(generator: SchemaGenerator, type: KType, inputType: Boolean): GraphQLType {
53-
val cacheKey = TypesCacheKey(type, inputType)
54-
val cachedType = generator.cache.get(cacheKey)
52+
private fun objectFromReflection(generator: SchemaGenerator, type: KType, inputType: Boolean, annotations: List<Annotation>): GraphQLType {
53+
val cachedType = generator.cache.get(type, inputType, annotations)
5554

5655
if (cachedType != null) {
5756
return cachedType
5857
}
5958

6059
val kClass = type.getKClass()
6160

62-
return generator.cache.buildIfNotUnderConstruction(kClass, inputType) {
63-
val graphQLType = getGraphQLType(generator, kClass, inputType, type)
61+
return generator.cache.buildIfNotUnderConstruction(kClass, inputType, annotations) {
62+
val graphQLType = getGraphQLType(generator, kClass, inputType, type, annotations)
6463
generator.config.hooks.willAddGraphQLTypeToSchema(type, graphQLType)
6564
}
6665
}
6766

68-
private fun getGraphQLType(generator: SchemaGenerator, kClass: KClass<*>, inputType: Boolean, type: KType): GraphQLType = when {
67+
private fun getGraphQLType(generator: SchemaGenerator, kClass: KClass<*>, inputType: Boolean, type: KType, fieldAnnotations: List<Annotation>): GraphQLType = when {
6968
kClass.isEnum() -> @Suppress("UNCHECKED_CAST") (generateEnum(generator, kClass as KClass<Enum<*>>))
70-
kClass.isListType() -> generateList(generator, type, inputType)
71-
kClass.isUnion() -> generateUnion(generator, kClass)
69+
kClass.isListType() -> generateList(generator, type, inputType, fieldAnnotations)
70+
kClass.isUnion(fieldAnnotations) -> generateUnion(generator, kClass, fieldAnnotations.getUnionAnnotation())
7271
kClass.isInterface() -> generateInterface(generator, kClass)
7372
inputType -> generateInputObject(generator, kClass)
7473
else -> generateObject(generator, kClass)

generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/internal/types/generateInterface.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ internal fun generateInterface(generator: SchemaGenerator, kClass: KClass<*>): G
6161
.filter { generator.config.hooks.isValidAdditionalType(it, inputType = false) }
6262
.forEach { generator.additionalTypes.add(AdditionalType(it.createType(), inputType = false)) }
6363

64-
val interfaceType = builder.build()
64+
val interfaceType: GraphQLInterfaceType = builder.build()
6565
generator.codeRegistry.typeResolver(interfaceType) { env: TypeResolutionEnvironment -> env.schema.getObjectType(env.getObject<Any>().javaClass.kotlin.getSimpleName()) }
6666
return generator.config.hooks.onRewireGraphQLType(interfaceType).safeCast()
6767
}

generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/internal/types/generateList.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import com.expediagroup.graphql.generator.internal.extensions.getWrappedType
2121
import graphql.schema.GraphQLList
2222
import kotlin.reflect.KType
2323

24-
internal fun generateList(generator: SchemaGenerator, type: KType, inputType: Boolean): GraphQLList {
25-
val wrappedType = generateGraphQLType(generator, type.getWrappedType(), inputType)
24+
internal fun generateList(generator: SchemaGenerator, type: KType, inputType: Boolean, annotations: List<Annotation> = emptyList()): GraphQLList {
25+
val wrappedType = generateGraphQLType(generator, type.getWrappedType(), inputType, annotations)
2626
return GraphQLList.list(wrappedType)
2727
}

generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/internal/types/generateProperty.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.expediagroup.graphql.generator.internal.types
1818

1919
import com.expediagroup.graphql.generator.SchemaGenerator
2020
import com.expediagroup.graphql.generator.directives.deprecatedDirectiveWithReason
21+
import com.expediagroup.graphql.generator.internal.extensions.getPropertyAnnotations
2122
import com.expediagroup.graphql.generator.internal.extensions.getPropertyDeprecationReason
2223
import com.expediagroup.graphql.generator.internal.extensions.getPropertyDescription
2324
import com.expediagroup.graphql.generator.internal.extensions.getPropertyName
@@ -32,7 +33,7 @@ import kotlin.reflect.KProperty
3233

3334
internal fun generateProperty(generator: SchemaGenerator, prop: KProperty<*>, parentClass: KClass<*>): GraphQLFieldDefinition {
3435
val typeFromHooks = generator.config.hooks.willResolveMonad(prop.returnType)
35-
val propertyType = generateGraphQLType(generator, type = typeFromHooks)
36+
val propertyType = generateGraphQLType(generator, type = typeFromHooks, annotations = prop.getPropertyAnnotations(parentClass))
3637
.safeCast<GraphQLOutputType>()
3738

3839
val propertyName = prop.getPropertyName(parentClass)

generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/internal/types/generateUnion.kt

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.expediagroup.graphql.generator.internal.types
1818

1919
import com.expediagroup.graphql.generator.SchemaGenerator
20+
import com.expediagroup.graphql.generator.annotations.GraphQLUnion
2021
import com.expediagroup.graphql.generator.extensions.unwrapType
2122
import com.expediagroup.graphql.generator.internal.extensions.getGraphQLDescription
2223
import com.expediagroup.graphql.generator.internal.extensions.getSimpleName
@@ -29,25 +30,49 @@ import graphql.schema.GraphQLUnionType
2930
import kotlin.reflect.KClass
3031
import kotlin.reflect.full.createType
3132

32-
internal fun generateUnion(generator: SchemaGenerator, kClass: KClass<*>): GraphQLUnionType {
33+
internal fun generateUnion(generator: SchemaGenerator, kClass: KClass<*>, unionAnnotation: GraphQLUnion? = null): GraphQLUnionType {
34+
return if (unionAnnotation != null) {
35+
generateUnionFromAnnotation(generator, unionAnnotation)
36+
} else {
37+
generateUnionFromKClass(generator, kClass)
38+
}
39+
}
40+
41+
private fun generateUnionFromAnnotation(generator: SchemaGenerator, unionAnnotation: GraphQLUnion): GraphQLUnionType {
3342
val builder = GraphQLUnionType.newUnionType()
34-
builder.name(kClass.getSimpleName())
43+
builder.name(unionAnnotation.name)
44+
builder.description(unionAnnotation.description)
45+
46+
val possibleTypes = unionAnnotation.possibleTypes.toList()
47+
48+
return createUnion(generator, builder, possibleTypes, unionAnnotation.name)
49+
}
50+
51+
private fun generateUnionFromKClass(generator: SchemaGenerator, kClass: KClass<*>): GraphQLUnionType {
52+
val builder = GraphQLUnionType.newUnionType()
53+
val name = kClass.getSimpleName()
54+
builder.name(name)
3555
builder.description(kClass.getGraphQLDescription())
3656

3757
generateDirectives(generator, kClass, DirectiveLocation.UNION).forEach {
3858
builder.withDirective(it)
3959
}
4060

41-
generator.classScanner.getSubTypesOf(kClass)
42-
.map { generateGraphQLType(generator, it.createType()) }
61+
val types = generator.classScanner.getSubTypesOf(kClass)
62+
63+
return createUnion(generator, builder, types, name)
64+
}
65+
66+
private fun createUnion(generator: SchemaGenerator, builder: GraphQLUnionType.Builder, types: List<KClass<*>>, name: String): GraphQLUnionType {
67+
types.map { generateGraphQLType(generator, it.createType()) }
4368
.forEach {
4469
when (val unwrappedType = it.unwrapType()) {
4570
is GraphQLTypeReference -> builder.possibleType(unwrappedType)
4671
is GraphQLObjectType -> builder.possibleType(unwrappedType)
4772
}
4873
}
4974

50-
val unionType = builder.build()
75+
val unionType: GraphQLUnionType = builder.build()
5176
generator.codeRegistry.typeResolver(unionType) { env: TypeResolutionEnvironment -> env.schema.getObjectType(env.getObject<Any>().javaClass.kotlin.getSimpleName()) }
52-
return generator.config.hooks.onRewireGraphQLType(unionType).safeCast()
77+
return generator.config.hooks.onRewireGraphQLType(unionType, null, generator.codeRegistry).safeCast()
5378
}

generator/graphql-kotlin-schema-generator/src/test/kotlin/com/expediagroup/graphql/generator/internal/extensions/KClassExtensionsTest.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.expediagroup.graphql.generator.internal.extensions
1818

1919
import com.expediagroup.graphql.generator.annotations.GraphQLIgnore
2020
import com.expediagroup.graphql.generator.annotations.GraphQLName
21+
import com.expediagroup.graphql.generator.annotations.GraphQLUnion
2122
import com.expediagroup.graphql.generator.exceptions.CouldNotGetNameOfKClassException
2223
import com.expediagroup.graphql.generator.hooks.NoopSchemaGeneratorHooks
2324
import com.expediagroup.graphql.generator.hooks.SchemaGeneratorHooks
@@ -149,6 +150,17 @@ open class KClassExtensionsTest {
149150
fun getTest() = 1
150151
}
151152

153+
class One(val value: String)
154+
class Two(val value: String)
155+
156+
class TestQuery {
157+
@GraphQLUnion(name = "Number", possibleTypes = [One::class, Two::class])
158+
fun customUnion(): Any = One("1")
159+
160+
@GraphQLUnion(name = "InvalidUnion", possibleTypes = [One::class, Two::class])
161+
fun invalidCustomUnion(): Int = 1
162+
}
163+
152164
private class FilterHooks : SchemaGeneratorHooks {
153165
override fun isValidProperty(kClass: KClass<*>, property: KProperty<*>) =
154166
property.name.contains("filteredProperty").not()
@@ -273,9 +285,13 @@ open class KClassExtensionsTest {
273285
@Test
274286
fun `test graphql union extension`() {
275287
assertTrue(TestUnion::class.isUnion())
288+
val customAnnotationUnion = TestQuery::customUnion
289+
assertTrue(customAnnotationUnion.returnType.getKClass().isUnion(customAnnotationUnion.annotations))
276290
assertFalse(InvalidPropertyUnionInterface::class.isUnion())
277291
assertFalse(InvalidFunctionUnionInterface::class.isUnion())
278292
assertFalse(Pet::class.isUnion())
293+
val invalidAnnotationUnion = TestQuery::invalidCustomUnion
294+
assertFalse(invalidAnnotationUnion.returnType.getKClass().isUnion(invalidAnnotationUnion.annotations))
279295
}
280296

281297
// TODO remove JUnit condition once we only build artifacts using Java 11

0 commit comments

Comments
 (0)