diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/ClientApiGenerator.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/ClientApiGenerator.kt index 0b373af00..91e2e3c78 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/ClientApiGenerator.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/ClientApiGenerator.kt @@ -67,7 +67,6 @@ class ClientApiGenerator internal constructor( ) { constructor(config: CodeGenConfig, document: Document) : this(config, SchemaIndex(document)) - private val document = schemaIndex.document private val generatedClasses = mutableSetOf() private val typeUtils = TypeUtils(getDatatypesPackageName(), config, schemaIndex) private val javaReservedKeywordSanitizer = JavaReservedKeywordSanitizer() @@ -412,37 +411,37 @@ class ClientApiGenerator internal constructor( originalMethodName.plus("GraphQLQuery") } + private fun createProjectionClass(clazzName: String): TypeSpec.Builder { + val baseProjectionClass = ClassName.get(BaseSubProjectionNode::class.java) + val baseProjectionType = + ParameterizedTypeName.get(baseProjectionClass, TypeVariableName.get("?"), TypeVariableName.get("?")) + val parentType = TypeVariableName.get("PARENT").withBounds(baseProjectionType) + val rootType = TypeVariableName.get("ROOT").withBounds(baseProjectionType) + + return TypeSpec + .classBuilder(clazzName) + .addOptionalGeneratedAnnotation(config) + .addTypeVariable(parentType) + .addTypeVariable(rootType) + .addModifiers(Modifier.PUBLIC) + .superclass(ParameterizedTypeName.get(baseProjectionClass, TypeVariableName.get("PARENT"), TypeVariableName.get("ROOT"))) + } + + private fun createRootProjectionConstructor(typeName: String): MethodSpec = + MethodSpec + .constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addCode("""super(null, null, java.util.Optional.of("$typeName"));""") + .build() + private fun createRootProjection( type: TypeDefinition<*>, prefix: String, ): CodeGenResult { val clazzName = "${prefix}ProjectionRoot" - val className = ClassName.get(BaseSubProjectionNode::class.java) - val parentJavaType = - TypeVariableName - .get( - "PARENT", - ).withBounds(ParameterizedTypeName.get(className, TypeVariableName.get("?"), TypeVariableName.get("?"))) - val rootJavaType = - TypeVariableName - .get( - "ROOT", - ).withBounds(ParameterizedTypeName.get(className, TypeVariableName.get("?"), TypeVariableName.get("?"))) val javaType = - TypeSpec - .classBuilder(clazzName) - .addOptionalGeneratedAnnotation(config) - .addTypeVariable(parentJavaType) - .addTypeVariable(rootJavaType) - .addModifiers(Modifier.PUBLIC) - .superclass(ParameterizedTypeName.get(className, TypeVariableName.get("PARENT"), TypeVariableName.get("ROOT"))) - .addMethod( - MethodSpec - .constructorBuilder() - .addModifiers(Modifier.PUBLIC) - .addCode("""super(null, null, java.util.Optional.of("${type.name}"));""") - .build(), - ) + createProjectionClass(clazzName) + .addMethod(createRootProjectionConstructor(type.name)) val typeVariable = TypeVariableName.get("$clazzName") javaType.addMethod( @@ -617,32 +616,9 @@ class ClientApiGenerator internal constructor( private fun createEntitiesRootProjection(federatedTypes: List): CodeGenResult { val clazzName = "EntitiesProjectionRoot" - val className = ClassName.get(BaseSubProjectionNode::class.java) - val parentType = - TypeVariableName - .get( - "PARENT", - ).withBounds(ParameterizedTypeName.get(className, TypeVariableName.get("?"), TypeVariableName.get("?"))) - val rootType = - TypeVariableName - .get( - "ROOT", - ).withBounds(ParameterizedTypeName.get(className, TypeVariableName.get("?"), TypeVariableName.get("?"))) val javaType = - TypeSpec - .classBuilder(clazzName) - .addOptionalGeneratedAnnotation(config) - .addTypeVariable(parentType) - .addTypeVariable(rootType) - .addModifiers(Modifier.PUBLIC) - .superclass(ParameterizedTypeName.get(className, TypeVariableName.get("PARENT"), TypeVariableName.get("ROOT"))) - .addMethod( - MethodSpec - .constructorBuilder() - .addModifiers(Modifier.PUBLIC) - .addCode("""super(null, null, java.util.Optional.of("${"_entities"}"));""") - .build(), - ) + createProjectionClass(clazzName) + .addMethod(createRootProjectionConstructor("_entities")) if (generatedClasses.contains(clazzName)) return CodeGenResult.EMPTY else generatedClasses.add(clazzName) @@ -802,28 +778,11 @@ class ClientApiGenerator internal constructor( root: TypeSpec, prefix: String, ): Pair? { - val className = ClassName.get(BaseSubProjectionNode::class.java) val clazzName = "${prefix}Projection" if (generatedClasses.contains(clazzName)) return null else generatedClasses.add(clazzName) - val parentJavaType = - TypeVariableName - .get( - "PARENT", - ).withBounds(ParameterizedTypeName.get(className, TypeVariableName.get("?"), TypeVariableName.get("?"))) - val rootJavaType = - TypeVariableName - .get( - "ROOT", - ).withBounds(ParameterizedTypeName.get(className, TypeVariableName.get("?"), TypeVariableName.get("?"))) val javaType = - TypeSpec - .classBuilder(clazzName) - .addOptionalGeneratedAnnotation(config) - .addTypeVariable(parentJavaType) - .addTypeVariable(rootJavaType) - .addModifiers(Modifier.PUBLIC) - .superclass(ParameterizedTypeName.get(className, TypeVariableName.get("PARENT"), TypeVariableName.get("ROOT"))) + createProjectionClass(clazzName) .addMethod( MethodSpec .constructorBuilder() diff --git a/graphql-dgs-codegen-shared-core/src/main/kotlin/com/netflix/graphql/dgs/client/codegen/InputValueSerializer.kt b/graphql-dgs-codegen-shared-core/src/main/kotlin/com/netflix/graphql/dgs/client/codegen/InputValueSerializer.kt index 521a3e194..a6753d64b 100644 --- a/graphql-dgs-codegen-shared-core/src/main/kotlin/com/netflix/graphql/dgs/client/codegen/InputValueSerializer.kt +++ b/graphql-dgs-codegen-shared-core/src/main/kotlin/com/netflix/graphql/dgs/client/codegen/InputValueSerializer.kt @@ -79,7 +79,7 @@ open class InputValueSerializer( val objectFields = propertyValues .asSequence() - .filter { (_, value) -> value != null } + .filter { (_, value) -> shouldSerializeProperty(value) } .map { (name, value) -> ObjectField(InputReservedKeywordSanitizer().desanitize(name), toValue(value)) } .toList() return ObjectValue @@ -88,6 +88,8 @@ open class InputValueSerializer( .build() } + protected open fun shouldSerializeProperty(value: Any?): Boolean = value != null + protected fun getOptionalValue(input: Any): Optional> { if (input is Value<*>) { return Optional.of(input) diff --git a/graphql-dgs-codegen-shared-core/src/main/kotlin/com/netflix/graphql/dgs/client/codegen/NullableInputValueSerializer.kt b/graphql-dgs-codegen-shared-core/src/main/kotlin/com/netflix/graphql/dgs/client/codegen/NullableInputValueSerializer.kt index 01f5c24c2..59a00b64c 100644 --- a/graphql-dgs-codegen-shared-core/src/main/kotlin/com/netflix/graphql/dgs/client/codegen/NullableInputValueSerializer.kt +++ b/graphql-dgs-codegen-shared-core/src/main/kotlin/com/netflix/graphql/dgs/client/codegen/NullableInputValueSerializer.kt @@ -16,38 +16,10 @@ package com.netflix.graphql.dgs.client.codegen -import graphql.language.NullValue -import graphql.language.ObjectField -import graphql.language.ObjectValue -import graphql.language.Value import graphql.schema.Coercing -import kotlin.reflect.full.allSuperclasses class NullableInputValueSerializer( scalars: Map, Coercing<*, *>> = emptyMap(), ) : InputValueSerializer(scalars) { - override fun toValue(input: Any?): Value<*> { - if (input == null) { - return NullValue.newNullValue().build() - } - - val optionalValue = getOptionalValue(input) - - if (optionalValue.isPresent) { - return optionalValue.get() - } - - val classes = (sequenceOf(input::class) + input::class.allSuperclasses.asSequence()) - Any::class - val propertyValues = getPropertyValues(classes, input) - - val objectFields = - propertyValues - .asSequence() - .map { (name, value) -> ObjectField(InputReservedKeywordSanitizer().desanitize(name), toValue(value)) } - .toList() - return ObjectValue - .newObjectValue() - .objectFields(objectFields) - .build() - } + override fun shouldSerializeProperty(value: Any?): Boolean = true }