diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/CodeGen.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/CodeGen.kt index 16db19d5e..3ae33e7b0 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/CodeGen.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/CodeGen.kt @@ -523,7 +523,8 @@ class CodeGenConfig( var implementSerializable: Boolean = false, var addGeneratedAnnotation: Boolean = false, var disableDatesInGeneratedAnnotation: Boolean = false, - var addDeprecatedAnnotation: Boolean = false + var addDeprecatedAnnotation: Boolean = false, + var nameTemplate: String? = null ) { val packageNameClient: String = "$packageName.$subPackageNameClient" diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/DataTypeGenerator.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/DataTypeGenerator.kt index cea660480..9e8a1eeba 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/DataTypeGenerator.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/DataTypeGenerator.kt @@ -18,9 +18,13 @@ package com.netflix.graphql.dgs.codegen.generators.java -import com.netflix.graphql.dgs.codegen.* +import com.netflix.graphql.dgs.codegen.CodeGenConfig +import com.netflix.graphql.dgs.codegen.CodeGenResult +import com.netflix.graphql.dgs.codegen.filterSkipped +import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName import com.netflix.graphql.dgs.codegen.generators.shared.SiteTarget import com.netflix.graphql.dgs.codegen.generators.shared.applyDirectivesJava +import com.netflix.graphql.dgs.codegen.shouldSkip import com.squareup.javapoet.ClassName import com.squareup.javapoet.CodeBlock import com.squareup.javapoet.FieldSpec @@ -71,7 +75,7 @@ class DataTypeGenerator(config: CodeGenConfig, document: Document) : BaseDataTyp logger.info("Generating data type {}", definition.name) - val name = definition.name + val name = definition.templatedClassName(config.nameTemplate) val unionTypes = document.getDefinitionsOfType(UnionTypeDefinition::class.java).asSequence().filter { union -> union.memberTypes.asSequence().map { it as TypeName }.any { it.name == name } }.map { it.name }.toList() @@ -168,7 +172,7 @@ class InputTypeGenerator(config: CodeGenConfig, document: Document) : BaseDataTy logger.info("Generating input type {}", definition.name) - val name = definition.name + val name = definition.templatedClassName(config.nameTemplate) val fieldDefinitions = definition.inputValueDefinitions.asSequence().map { val type = typeUtils.findReturnType(it.type) val defaultValue = it.defaultValue?.let { defVal -> diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/EnumTypeGenerator.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/EnumTypeGenerator.kt index 16c08899d..7652269cd 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/EnumTypeGenerator.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/EnumTypeGenerator.kt @@ -20,6 +20,7 @@ package com.netflix.graphql.dgs.codegen.generators.java import com.netflix.graphql.dgs.codegen.CodeGenConfig import com.netflix.graphql.dgs.codegen.CodeGenResult +import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName import com.netflix.graphql.dgs.codegen.generators.shared.SiteTarget import com.netflix.graphql.dgs.codegen.generators.shared.applyDirectivesJava import com.netflix.graphql.dgs.codegen.shouldSkip @@ -44,7 +45,7 @@ class EnumTypeGenerator(private val config: CodeGenConfig) { val javaType = TypeSpec - .enumBuilder(definition.name) + .enumBuilder(definition.templatedClassName(config.nameTemplate)) .addModifiers(Modifier.PUBLIC) .addOptionalGeneratedAnnotation(config) diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/InterfaceGenerator.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/InterfaceGenerator.kt index ff9fcd845..cc8053101 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/InterfaceGenerator.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/InterfaceGenerator.kt @@ -22,12 +22,18 @@ import com.netflix.graphql.dgs.codegen.CodeGenConfig import com.netflix.graphql.dgs.codegen.CodeGenResult import com.netflix.graphql.dgs.codegen.filterSkipped import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.capitalized +import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName import com.netflix.graphql.dgs.codegen.shouldSkip import com.squareup.javapoet.ClassName import com.squareup.javapoet.JavaFile import com.squareup.javapoet.MethodSpec import com.squareup.javapoet.TypeSpec -import graphql.language.* +import graphql.language.Document +import graphql.language.FieldDefinition +import graphql.language.InterfaceTypeDefinition +import graphql.language.InterfaceTypeExtensionDefinition +import graphql.language.ObjectTypeDefinition +import graphql.language.TypeName import org.slf4j.Logger import org.slf4j.LoggerFactory import javax.lang.model.element.Modifier @@ -51,7 +57,7 @@ class InterfaceGenerator(private val config: CodeGenConfig, private val document } logger.info("Generating type {}", definition.name) - val javaType = TypeSpec.interfaceBuilder(definition.name) + val javaType = TypeSpec.interfaceBuilder(definition.templatedClassName(config.nameTemplate)) .addOptionalGeneratedAnnotation(config) .addModifiers(Modifier.PUBLIC) diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinDataTypeGenerator.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinDataTypeGenerator.kt index 968a6cec5..e6a78efaa 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinDataTypeGenerator.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinDataTypeGenerator.kt @@ -22,6 +22,7 @@ import com.netflix.graphql.dgs.codegen.CodeGenConfig import com.netflix.graphql.dgs.codegen.CodeGenResult import com.netflix.graphql.dgs.codegen.filterSkipped import com.netflix.graphql.dgs.codegen.generators.java.InputTypeGenerator +import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName import com.netflix.graphql.dgs.codegen.generators.shared.applyDirectivesKotlin import com.netflix.graphql.dgs.codegen.generators.shared.generateKotlinCode import com.netflix.graphql.dgs.codegen.shouldSkip @@ -84,7 +85,7 @@ class KotlinDataTypeGenerator(config: CodeGenConfig, document: Document) : ) } val interfaces = definition.implements + extensions.flatMap { it.implements } - return generate(definition.name, fields, interfaces, document, definition.description, definition.directives) + return generate(definition.templatedClassName(config.nameTemplate), fields, interfaces, document, definition.description, definition.directives) } } @@ -139,7 +140,7 @@ class KotlinInputTypeGenerator(config: CodeGenConfig, document: Document) : } ) val interfaces = emptyList>() - return generate(definition.name, fields, interfaces, document, definition.description, definition.directives) + return generate(definition.templatedClassName(config.nameTemplate), fields, interfaces, document, definition.description, definition.directives) } } diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinEnumTypeGenerator.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinEnumTypeGenerator.kt index eaa098747..a66941960 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinEnumTypeGenerator.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinEnumTypeGenerator.kt @@ -22,6 +22,7 @@ import com.netflix.graphql.dgs.codegen.CodeGenConfig import com.netflix.graphql.dgs.codegen.CodeGenResult import com.netflix.graphql.dgs.codegen.generators.java.EnumTypeGenerator import com.netflix.graphql.dgs.codegen.generators.java.ReservedKeywordSanitizer +import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName import com.netflix.graphql.dgs.codegen.generators.shared.applyDirectivesKotlin import com.netflix.graphql.dgs.codegen.shouldSkip import com.squareup.kotlinpoet.FileSpec @@ -41,7 +42,7 @@ class KotlinEnumTypeGenerator(private val config: CodeGenConfig) { logger.info("Generating enum type ${definition.name}") - val kotlinType = TypeSpec.classBuilder(definition.name) + val kotlinType = TypeSpec.classBuilder(definition.templatedClassName(config.nameTemplate)) .addOptionalGeneratedAnnotation(config) .addModifiers(KModifier.ENUM) diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinInterfaceTypeGenerator.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinInterfaceTypeGenerator.kt index 7cc8f3321..81647ba30 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinInterfaceTypeGenerator.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinInterfaceTypeGenerator.kt @@ -20,6 +20,7 @@ package com.netflix.graphql.dgs.codegen.generators.kotlin import com.netflix.graphql.dgs.codegen.CodeGenConfig import com.netflix.graphql.dgs.codegen.CodeGenResult +import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName import com.netflix.graphql.dgs.codegen.shouldSkip import com.squareup.kotlinpoet.* import graphql.language.* @@ -46,7 +47,7 @@ class KotlinInterfaceTypeGenerator(private val config: CodeGenConfig, private va logger.info("Generating type {}", definition.name) - val interfaceBuilder = TypeSpec.interfaceBuilder(definition.name) + val interfaceBuilder = TypeSpec.interfaceBuilder(definition.templatedClassName(config.nameTemplate)) .addOptionalGeneratedAnnotation(config) if (definition.description != null) { interfaceBuilder.addKdoc("%L", definition.description.sanitizeKdoc()) diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2DataTypes.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2DataTypes.kt index ff88de1d8..767882fb3 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2DataTypes.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2DataTypes.kt @@ -33,6 +33,7 @@ import com.netflix.graphql.dgs.codegen.generators.kotlin.sanitizeKdoc import com.netflix.graphql.dgs.codegen.generators.kotlin.suppressInapplicableJvmNameAnnotation import com.netflix.graphql.dgs.codegen.generators.kotlin.toKtTypeName import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.capitalized +import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName import com.netflix.graphql.dgs.codegen.generators.shared.SchemaExtensionsUtils.findTypeExtensions import com.netflix.graphql.dgs.codegen.generators.shared.excludeSchemaTypeExtension import com.netflix.graphql.dgs.codegen.shouldSkip @@ -165,7 +166,7 @@ fun generateKotlin2DataTypes( .build() // create the data class - val typeSpec = TypeSpec.classBuilder(typeDefinition.name) + val typeSpec = TypeSpec.classBuilder(typeDefinition.templatedClassName(config.nameTemplate)) .addOptionalGeneratedAnnotation(config) // add docs if available .apply { diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2EnumTypes.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2EnumTypes.kt index d9a4a262a..4f9334233 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2EnumTypes.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2EnumTypes.kt @@ -22,6 +22,7 @@ import com.netflix.graphql.dgs.codegen.CodeGenConfig import com.netflix.graphql.dgs.codegen.generators.kotlin.addEnumConstants import com.netflix.graphql.dgs.codegen.generators.kotlin.addOptionalGeneratedAnnotation import com.netflix.graphql.dgs.codegen.generators.kotlin.sanitizeKdoc +import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName import com.netflix.graphql.dgs.codegen.generators.shared.SchemaExtensionsUtils.findEnumExtensions import com.netflix.graphql.dgs.codegen.generators.shared.applyDirectivesKotlin import com.netflix.graphql.dgs.codegen.generators.shared.excludeSchemaTypeExtension @@ -59,7 +60,7 @@ fun generateKotlin2EnumTypes( .build() // create the enum class - val enumSpec = TypeSpec.classBuilder(enumDefinition.name) + val enumSpec = TypeSpec.classBuilder(enumDefinition.templatedClassName(config.nameTemplate)) .addOptionalGeneratedAnnotation(config) .addModifiers(KModifier.ENUM) // add docs if available diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2InputTypes.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2InputTypes.kt index 02a5bf379..1d91830d2 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2InputTypes.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2InputTypes.kt @@ -26,6 +26,7 @@ import com.netflix.graphql.dgs.codegen.generators.kotlin.KotlinTypeUtils import com.netflix.graphql.dgs.codegen.generators.kotlin.ReservedKeywordFilter import com.netflix.graphql.dgs.codegen.generators.kotlin.addOptionalGeneratedAnnotation import com.netflix.graphql.dgs.codegen.generators.kotlin.sanitizeKdoc +import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName import com.netflix.graphql.dgs.codegen.generators.shared.SchemaExtensionsUtils.findInputExtensions import com.netflix.graphql.dgs.codegen.generators.shared.excludeSchemaTypeExtension import com.netflix.graphql.dgs.codegen.generators.shared.generateKotlinCode @@ -71,7 +72,7 @@ fun generateKotlin2InputTypes( val typeName = ClassName(config.packageNameTypes, inputDefinition.name) // create the input class - val typeSpec = TypeSpec.classBuilder(typeName) + val typeSpec = TypeSpec.classBuilder(inputDefinition.templatedClassName(config.nameTemplate)) .addOptionalGeneratedAnnotation(config) // add docs if available .apply { diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2Interfaces.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2Interfaces.kt index 097283e6e..8dab1e185 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2Interfaces.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2Interfaces.kt @@ -26,6 +26,7 @@ import com.netflix.graphql.dgs.codegen.generators.kotlin.jsonTypeInfoAnnotation import com.netflix.graphql.dgs.codegen.generators.kotlin.jvmNameAnnotation import com.netflix.graphql.dgs.codegen.generators.kotlin.sanitizeKdoc import com.netflix.graphql.dgs.codegen.generators.kotlin.suppressInapplicableJvmNameAnnotation +import com.netflix.graphql.dgs.codegen.generators.shared.CodeGeneratorUtils.templatedClassName import com.netflix.graphql.dgs.codegen.generators.shared.SchemaExtensionsUtils.findInterfaceExtensions import com.netflix.graphql.dgs.codegen.generators.shared.SchemaExtensionsUtils.findUnionExtensions import com.netflix.graphql.dgs.codegen.generators.shared.excludeSchemaTypeExtension @@ -82,7 +83,7 @@ fun generateKotlin2Interfaces( val overrideFields = typeLookup.overrideFields(implementedInterfaces) // create the interface - val interfaceSpec = TypeSpec.interfaceBuilder(interfaceDefinition.name) + val interfaceSpec = TypeSpec.interfaceBuilder(interfaceDefinition.templatedClassName(config.nameTemplate)) .addOptionalGeneratedAnnotation(config) .addModifiers(KModifier.SEALED) // add docs if available diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/CodeGeneratorUtils.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/CodeGeneratorUtils.kt index d38ea18a0..c9a47f195 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/CodeGeneratorUtils.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/CodeGeneratorUtils.kt @@ -18,6 +18,12 @@ package com.netflix.graphql.dgs.codegen.generators.shared +import graphql.language.EnumTypeDefinition +import graphql.language.InputObjectTypeDefinition +import graphql.language.InterfaceTypeDefinition +import graphql.language.NamedNode +import graphql.language.ObjectTypeDefinition + object CodeGeneratorUtils { enum class Case { @@ -40,6 +46,37 @@ object CodeGeneratorUtils { fun String.capitalized(): String = replaceFirstChar(Character::toTitleCase) + /** + * Returns the name generated using [nameTemplate]. If [nameTemplate] is null, returns the name of the node. + * + * The following variables are available in the template: + * - name: the original name of the node + * - schemaType: the GraphQL Schema type of the node (Type, Input, Interface, Enum) + * + * Examples: + * Given a node named "Person" and schema type "Type", the following templates will generate the following names: + * - null -> "Person" + * - "{name}GraphQL{schemaType}" -> "PersonGraphQLType" + * - "{name}GraphQL" -> "PersonGraphQL" + * - "{name}{schemaType}" -> "PersonType" + */ + fun NamedNode<*>.templatedClassName(nameTemplate: String?): String = + nameTemplate + ?.replace( + "{name}", + this.name + ) + ?.replace( + "{schemaType}", + when (this) { + is ObjectTypeDefinition -> "Type" + is InputObjectTypeDefinition -> "Input" + is InterfaceTypeDefinition -> "Interface" + is EnumTypeDefinition -> "Enum" + else -> "" + } + ) ?: this.name + /** * Mostly copied from Apache Commons StringUtils.splitByCharacterType */ diff --git a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/CodeGenTest.kt b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/CodeGenTest.kt index 9ea9fdf10..42ba688ae 100644 --- a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/CodeGenTest.kt +++ b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/CodeGenTest.kt @@ -5040,4 +5040,23 @@ It takes a title and such. ).generate() assertThat(result.javaDataTypes[0].typeSpec.fieldSpecs[1].type.toString() == "java.lang.String") } + + @TemplateClassNameTest + fun generateSerializedDataClassWithCustomName( + schema: String, + nameTemplate: String?, + expectedName: String + ) { + val dataTypes = CodeGen( + CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName, + nameTemplate = nameTemplate + ) + ) + .generate() + .javaSources() + + assertThat(dataTypes.firstOrNull()?.typeSpec?.name).isEqualTo(expectedName) + } } diff --git a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinCodeGenTest.kt b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinCodeGenTest.kt index 0a16f70df..d09fdf83f 100644 --- a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinCodeGenTest.kt +++ b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinCodeGenTest.kt @@ -4176,4 +4176,21 @@ It takes a title and such. assertThat(superinterfaces).contains("com.netflix.graphql.dgs.codegen.tests.generated.types.A") assertThat(superinterfaces).contains("com.netflix.graphql.dgs.codegen.tests.generated.types.B") } + + @TemplateClassNameTest + fun `Should generate class names based on template`( + schema: String, + nameTemplate: String?, + expectedName: String + ) { + val dataTypes = CodeGen( + CodeGenConfig( + schemas = setOf(schema), + language = Language.KOTLIN, + nameTemplate = nameTemplate + ) + ).generate().kotlinSources() + + assertThat(dataTypes.firstOrNull()?.name).isEqualTo(expectedName) + } } diff --git a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/Kotline2CodeGenTest.kt b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/Kotline2CodeGenTest.kt index c17ab3874..80b3afcd3 100644 --- a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/Kotline2CodeGenTest.kt +++ b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/Kotline2CodeGenTest.kt @@ -28,23 +28,7 @@ import java.io.Serializable class Kotline2CodeGenTest { @Test fun generateSerializableDataClass() { - val schema = """ - type Person { - firstname: String - lastname: String - } - """.trimIndent() - - val codeGenResult = CodeGen( - CodeGenConfig( - schemas = setOf(schema), - packageName = basePackageName, - language = Language.KOTLIN, - generateKotlinNullableClasses = true, - generateKotlinClosureProjections = true, - implementSerializable = true - ) - ).generate() + val codeGenResult = CodeGen(getTestCodeGenConfig()).generate() val dataTypes = codeGenResult.kotlinDataTypes @@ -134,4 +118,32 @@ class Kotline2CodeGenTest { assertCompilesKotlin(result.kotlinEnumTypes) } + + @TemplateClassNameTest + fun generateSerializedDataClassWithCustomName( + schema: String, + nameTemplate: String?, + expectedName: String + ) { + val dataTypes = CodeGen(getTestCodeGenConfig(nameTemplate = nameTemplate, schema = schema)) + .generate() + .kotlinSources() + + assertThat(dataTypes.firstOrNull()?.name).isEqualTo(expectedName) + } + + companion object { + private fun getTestCodeGenConfig( + nameTemplate: String? = null, + schema: String = PERSON_TYPE_SCHEMA + ): CodeGenConfig = CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName, + language = Language.KOTLIN, + generateKotlinNullableClasses = true, + generateKotlinClosureProjections = true, + implementSerializable = true, + nameTemplate = nameTemplate + ) + } } diff --git a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/TestUtils.kt b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/TestUtils.kt index 578dd6e48..027185092 100644 --- a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/TestUtils.kt +++ b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/TestUtils.kt @@ -34,6 +34,8 @@ import org.jetbrains.kotlin.cli.common.messages.MessageRenderer import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler import org.jetbrains.kotlin.config.Services +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.CsvSource import org.junit.platform.commons.util.ReflectionUtils import java.io.File import java.lang.reflect.Method @@ -171,6 +173,38 @@ fun TypeSpec.assertJavaGeneratedAnnotation(shouldHaveDate: Boolean) { fun AnnotationSpec.canonicalName(): String = (type as ClassName).canonicalName() fun KAnnotationSpec.canonicalName() = (typeName as KClassName).canonicalName +@ParameterizedTest +@CsvSource( + value = [ + "'$PERSON_TYPE_SCHEMA',,Person", + "'$PERSON_TYPE_SCHEMA',{name}Dto,PersonDto", + "'$PERSON_TYPE_SCHEMA',{name}{schemaType}Dto,PersonTypeDto", + "'$PERSON_TYPE_SCHEMA',{name}GraphQL{schemaType},PersonGraphQLType", + "'$PERSON_TYPE_SCHEMA',{name}{schemaType},PersonType", + "'$PERSON_INPUT_SCHEMA',,Person", + "'$PERSON_INPUT_SCHEMA',{name}Dto,PersonDto", + "'$PERSON_INPUT_SCHEMA',{name}{schemaType}Dto,PersonInputDto", + "'$PERSON_INPUT_SCHEMA',{name}GraphQL{schemaType},PersonGraphQLInput", + "'$PERSON_INPUT_SCHEMA',{name}{schemaType},PersonInput", + "'$PERSON_INTERFACE_SCHEMA',,Person", + "'$PERSON_INTERFACE_SCHEMA',{name}Dto,PersonDto", + "'$PERSON_INTERFACE_SCHEMA',{name}{schemaType}Dto,PersonInterfaceDto", + "'$PERSON_INTERFACE_SCHEMA',{name}GraphQL{schemaType},PersonGraphQLInterface", + "'$PERSON_INTERFACE_SCHEMA',{name}{schemaType},PersonInterface", + "'$ENUM_SCHEMA',,Color", + "'$ENUM_SCHEMA',{name}Dto,ColorDto", + "'$ENUM_SCHEMA',{name}{schemaType}Dto,ColorEnumDto", + "'$ENUM_SCHEMA',{name}GraphQL{schemaType},ColorGraphQLEnum", + "'$ENUM_SCHEMA',{name}{schemaType},ColorEnum" + ] +) +@Target(AnnotationTarget.FUNCTION) +annotation class TemplateClassNameTest + +const val PERSON_TYPE_SCHEMA: String = "type Person { firstname: String, lastname: String }" +const val PERSON_INPUT_SCHEMA = "input Person { firstname: String, lastname: String }" +const val PERSON_INTERFACE_SCHEMA = "interface Person { firstname: String, lastname: String }" +const val ENUM_SCHEMA = "enum Color { RED, GREEN, BLUE }" const val basePackageName = "com.netflix.graphql.dgs.codegen.tests.generated" const val typesPackageName = "$basePackageName.types" const val dataFetcherPackageName = "$basePackageName.datafetchers" diff --git a/graphql-dgs-codegen-gradle/src/main/kotlin/com/netflix/graphql/dgs/codegen/gradle/GenerateJavaTask.kt b/graphql-dgs-codegen-gradle/src/main/kotlin/com/netflix/graphql/dgs/codegen/gradle/GenerateJavaTask.kt index 8ec1162b8..e8ee92464 100644 --- a/graphql-dgs-codegen-gradle/src/main/kotlin/com/netflix/graphql/dgs/codegen/gradle/GenerateJavaTask.kt +++ b/graphql-dgs-codegen-gradle/src/main/kotlin/com/netflix/graphql/dgs/codegen/gradle/GenerateJavaTask.kt @@ -25,6 +25,7 @@ import org.gradle.api.DefaultTask import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.model.ObjectFactory import org.gradle.api.tasks.* +import org.gradle.api.tasks.Optional import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper import java.io.File import java.nio.file.Paths @@ -159,6 +160,10 @@ open class GenerateJavaTask @Inject constructor( @Input var includeClassImports = mutableMapOf>() + @Input + @Optional + var nameTemplate: String? = null + @Classpath val dgsCodegenClasspath: ConfigurableFileCollection = objectFactory.fileCollection().from( project.configurations.findByName("dgsCodegen") @@ -216,7 +221,8 @@ open class GenerateJavaTask @Inject constructor( includeImports = includeImports, includeEnumImports = includeEnumImports, includeClassImports = includeClassImports, - generateCustomAnnotations = generateCustomAnnotations + generateCustomAnnotations = generateCustomAnnotations, + nameTemplate = nameTemplate ) logger.info("Codegen config: {}", config) diff --git a/graphql-dgs-codegen-gradle/src/test/kotlin/com/netflix/graphql/dgs/CodegenGradlePluginTest.kt b/graphql-dgs-codegen-gradle/src/test/kotlin/com/netflix/graphql/dgs/CodegenGradlePluginTest.kt index 5533be912..feae7c681 100644 --- a/graphql-dgs-codegen-gradle/src/test/kotlin/com/netflix/graphql/dgs/CodegenGradlePluginTest.kt +++ b/graphql-dgs-codegen-gradle/src/test/kotlin/com/netflix/graphql/dgs/CodegenGradlePluginTest.kt @@ -24,6 +24,8 @@ import org.assertj.core.api.Assertions.assertThat import org.gradle.testkit.runner.GradleRunner import org.gradle.testkit.runner.TaskOutcome.SUCCESS import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.CsvSource import java.io.File /** @@ -114,6 +116,62 @@ class CodegenGradlePluginTest { assertThat(File(EXPECTED_DEFAULT_PATH + "Result.java").exists()).isTrue } + @Test + fun sourcesGenerated_WithNameTemplate() { + // build a project + val result = GradleRunner.create() + .withProjectDir(File("src/test/resources/test-project/")) + .withPluginClasspath() + .withArguments( + "--stacktrace", + "-c", + "smoke_test_settings_custom_name_template.gradle", + "-b", + "build_custom_name_template.gradle", + "clean", + "build" + ) + .forwardOutput() + .withDebug(true) + .build() + + // Verify the result + assertThat(result.task(":build")).extracting { it?.outcome }.isEqualTo(SUCCESS) + // Verify that POJOs are generated in the configured directory + assertThat(File(EXPECTED_DEFAULT_PATH + "ResultGraphQLType.java").exists()).isTrue + assertThat(File(EXPECTED_DEFAULT_PATH + "FilterGraphQLInput.java").exists()).isTrue + } + + @ParameterizedTest + @CsvSource( + "smoke_test_settings_custom_name_template_kotlin.gradle,build_custom_name_template_kotlin.gradle", + "smoke_test_settings_custom_name_template_kotlin2.gradle,build_custom_name_template_kotlin2.gradle" + ) + fun sourcesGenerated_WithNameTemplate_Kotlin(settingsFile: String, buildFile: String) { + // build a project + val result = GradleRunner.create() + .withProjectDir(File("src/test/resources/test-project/")) + .withPluginClasspath() + .withArguments( + "--stacktrace", + "-c", + settingsFile, + "-b", + buildFile, + "clean", + "build" + ) + .forwardOutput() + .withDebug(true) + .build() + + // Verify the result + assertThat(result.task(":build")).extracting { it?.outcome }.isEqualTo(SUCCESS) + // Verify that POJOs are generated in the configured directory + assertThat(File(EXPECTED_DEFAULT_PATH + "ResultGraphQLType.kt").exists()).isTrue + assertThat(File(EXPECTED_DEFAULT_PATH + "FilterGraphQLInput.kt").exists()).isTrue + } + @Test fun sourcesGenerated_OmitNullInputFields() { // build a project diff --git a/graphql-dgs-codegen-gradle/src/test/resources/test-project/build_custom_name_template.gradle b/graphql-dgs-codegen-gradle/src/test/resources/test-project/build_custom_name_template.gradle new file mode 100644 index 000000000..3358f18f5 --- /dev/null +++ b/graphql-dgs-codegen-gradle/src/test/resources/test-project/build_custom_name_template.gradle @@ -0,0 +1,42 @@ +/* + * + * Copyright 2020 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +plugins { + id 'java' + id 'com.netflix.dgs.codegen' +} + +configurations { + // injected by Gradle Runner through test configuration, see CodegenGradlePluginTest + CodeGenConfiguration.exclude group: "com.netflix.graphql.dgs.codegen", module: "graphql-dgs-codegen-core" +} + +generateJava { + schemaPaths = ["${projectDir}/src/main/resources/schema"] + packageName = 'com.netflix.testproject.graphql' + typeMapping = [Date:"java.time.LocalDateTime"] + nameTemplate = "{name}GraphQL{schemaType}" +} + +codegen.clientCoreConventionsEnabled = false + +tasks.register("copyMainSources", Copy) { + //This should be enough to depend on the 'generateJava' task + from sourceSets.main.java + into "build/tmp/main" +} \ No newline at end of file diff --git a/graphql-dgs-codegen-gradle/src/test/resources/test-project/build_custom_name_template_kotlin.gradle b/graphql-dgs-codegen-gradle/src/test/resources/test-project/build_custom_name_template_kotlin.gradle new file mode 100644 index 000000000..5db5e6f18 --- /dev/null +++ b/graphql-dgs-codegen-gradle/src/test/resources/test-project/build_custom_name_template_kotlin.gradle @@ -0,0 +1,43 @@ +/* + * + * Copyright 2020 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +plugins { + id 'java' + id 'com.netflix.dgs.codegen' +} + +configurations { + // injected by Gradle Runner through test configuration, see CodegenGradlePluginTest + CodeGenConfiguration.exclude group: "com.netflix.graphql.dgs.codegen", module: "graphql-dgs-codegen-core" +} + +generateJava { + schemaPaths = ["${projectDir}/src/main/resources/schema"] + packageName = 'com.netflix.testproject.graphql' + typeMapping = [Date:"java.time.LocalDateTime"] + language = "KOTLIN" + nameTemplate = "{name}GraphQL{schemaType}" +} + +codegen.clientCoreConventionsEnabled = false + +tasks.register("copyMainSources", Copy) { + //This should be enough to depend on the 'generateJava' task + from sourceSets.main.java + into "build/tmp/main" +} \ No newline at end of file diff --git a/graphql-dgs-codegen-gradle/src/test/resources/test-project/build_custom_name_template_kotlin2.gradle b/graphql-dgs-codegen-gradle/src/test/resources/test-project/build_custom_name_template_kotlin2.gradle new file mode 100644 index 000000000..4f8220027 --- /dev/null +++ b/graphql-dgs-codegen-gradle/src/test/resources/test-project/build_custom_name_template_kotlin2.gradle @@ -0,0 +1,46 @@ +/* + * + * Copyright 2020 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +plugins { + id 'java' + id 'com.netflix.dgs.codegen' +} + +configurations { + // injected by Gradle Runner through test configuration, see CodegenGradlePluginTest + CodeGenConfiguration.exclude group: "com.netflix.graphql.dgs.codegen", module: "graphql-dgs-codegen-core" +} + +generateJava { + schemaPaths = ["${projectDir}/src/main/resources/schema"] + packageName = 'com.netflix.testproject.graphql' + typeMapping = [Date:"java.time.LocalDateTime"] + language = "KOTLIN" + nameTemplate = "{name}GraphQL{schemaType}" + generateKotlinNullableClasses = true + generateKotlinClosureProjections = true + implementSerializable = true +} + +codegen.clientCoreConventionsEnabled = false + +tasks.register("copyMainSources", Copy) { + //This should be enough to depend on the 'generateJava' task + from sourceSets.main.java + into "build/tmp/main" +} \ No newline at end of file diff --git a/graphql-dgs-codegen-gradle/src/test/resources/test-project/smoke_test_settings_custom_name_template.gradle b/graphql-dgs-codegen-gradle/src/test/resources/test-project/smoke_test_settings_custom_name_template.gradle new file mode 100644 index 000000000..e013aa733 --- /dev/null +++ b/graphql-dgs-codegen-gradle/src/test/resources/test-project/smoke_test_settings_custom_name_template.gradle @@ -0,0 +1,19 @@ +/* + * + * Copyright 2020 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +rootProject.buildFileName = 'build_custom_name_template.gradle' diff --git a/graphql-dgs-codegen-gradle/src/test/resources/test-project/smoke_test_settings_custom_name_template_kotlin.gradle b/graphql-dgs-codegen-gradle/src/test/resources/test-project/smoke_test_settings_custom_name_template_kotlin.gradle new file mode 100644 index 000000000..c436f84e4 --- /dev/null +++ b/graphql-dgs-codegen-gradle/src/test/resources/test-project/smoke_test_settings_custom_name_template_kotlin.gradle @@ -0,0 +1,19 @@ +/* + * + * Copyright 2020 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +rootProject.buildFileName = 'build_custom_name_template_kotlin.gradle' diff --git a/graphql-dgs-codegen-gradle/src/test/resources/test-project/smoke_test_settings_custom_name_template_kotlin2.gradle b/graphql-dgs-codegen-gradle/src/test/resources/test-project/smoke_test_settings_custom_name_template_kotlin2.gradle new file mode 100644 index 000000000..408a037b3 --- /dev/null +++ b/graphql-dgs-codegen-gradle/src/test/resources/test-project/smoke_test_settings_custom_name_template_kotlin2.gradle @@ -0,0 +1,19 @@ +/* + * + * Copyright 2020 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +rootProject.buildFileName = 'build_custom_name_template_kotlin2.gradle'