From dea87f9062ebb296a47bf9a80a589a4d18b3bbff Mon Sep 17 00:00:00 2001 From: lakshmisunid <87725994+lakshmisunid@users.noreply.github.com> Date: Fri, 14 Oct 2022 15:13:43 -0700 Subject: [PATCH 1/5] Iiea 10932 site targets (#6) * IIEA-10932 Added code to support site targets * IIEA-10932 Updated unit tests for Java changes * IIEA-10932 Fixed lint errors * IIEA-10932 Fixed lint errors in unit tests * IIEA-10932 Fixed the unit test imports * IIEA-10932 Fixed the unit tests failure when there is no custom annotations * IIEA-10932 Added more comments * IIEA-10932 Updated code as per review Co-authored-by: Lakshmi Vijayachandran --- .../generators/java/DataTypeGenerator.kt | 77 +++++---- .../generators/kotlin/KotlinPoetUtils.kt | 4 + .../generators/shared/ParserConstants.kt | 1 + .../codegen/generators/shared/SiteTarget.kt | 32 ++++ .../graphql/dgs/codegen/CodeGenTest.kt | 154 ++++++++++++++++++ .../graphql/dgs/codegen/KotlinCodeGenTest.kt | 62 +++++++ 6 files changed, 300 insertions(+), 30 deletions(-) create mode 100644 graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/SiteTarget.kt 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 eef548c2f..f13ae9faf 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 @@ -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.shared.ParserConstants +import com.netflix.graphql.dgs.codegen.generators.shared.SiteTarget import com.netflix.graphql.dgs.codegen.shouldSkip import com.squareup.javapoet.* import graphql.language.* @@ -179,18 +180,27 @@ abstract class BaseDataTypeGenerator( } /** - * Applies directives like customAnnotation + * Applies directives like customAnnotation, deprecated etc. The target value in the directives is used to decide where to apply the annotation. + * @input directives: list of directive that needs to be applied + * @return Pair of (map of target site and corresponding annotations) and comments */ - private fun applyDirectives(directives: List): Pair, String?> { + private fun applyDirectives(directives: List): Pair>, String?> { var commentFormat: String? = null return Pair( - directives.fold(mutableListOf()) { annotations, directive -> + directives.fold(mutableMapOf()) { annotations, directive -> val argumentMap = createArgumentMap(directive) + val siteTarget = if (argumentMap.containsKey(ParserConstants.SITE_TARGET)) (argumentMap[ParserConstants.SITE_TARGET] as StringValue).value.uppercase() else SiteTarget.DEFAULT.name if (directive.name == ParserConstants.CUSTOM_ANNOTATION && config.generateCustomAnnotations) { - annotations.add(customAnnotation(argumentMap, config)) + annotations[siteTarget] = if (annotations.containsKey(siteTarget)) { + var annotationList: MutableList = annotations[siteTarget]!! + annotationList.add(customAnnotation(argumentMap, config)) + annotationList + } else { + mutableListOf(customAnnotation(argumentMap, config)) + } } if (directive.name == ParserConstants.DEPRECATED) { - annotations.add(deprecatedAnnotation()) + annotations[siteTarget] = mutableListOf(deprecatedAnnotation()) if (argumentMap.containsKey(ParserConstants.REASON)) { val reason: String = (argumentMap[ParserConstants.REASON] as StringValue).value val replace = reason.substringAfter(ParserConstants.REPLACE_WITH_STR, "") @@ -229,7 +239,9 @@ abstract class BaseDataTypeGenerator( if (directives.isNotEmpty()) { val (annotations, comments) = applyDirectives(directives) - javaType.addAnnotations(annotations) + if (annotations.containsKey(SiteTarget.DEFAULT.name)) { + javaType.addAnnotations(annotations[SiteTarget.DEFAULT.name]) + } if (!comments.isNullOrBlank()) { javaType.addJavadoc("\$L", comments) } @@ -390,22 +402,10 @@ abstract class BaseDataTypeGenerator( FieldSpec.builder(returnType, ReservedKeywordSanitizer.sanitize(fieldDefinition.name)).addModifiers(Modifier.PRIVATE) } - if (fieldDefinition.directives.isNotEmpty()) { - val (annotations, comments) = applyDirectives(fieldDefinition.directives) - fieldBuilder.addAnnotations(annotations) - if (!comments.isNullOrBlank()) { - fieldBuilder.addJavadoc("\$L", comments) - } - } - if (fieldDefinition.description != null) { fieldBuilder.addJavadoc(fieldDefinition.description.sanitizeJavaDoc()) } - val field = fieldBuilder.build() - - javaType.addField(field) - val getterName = typeUtils.transformIfDefaultClassMethodExists("get${fieldDefinition.name[0].uppercase()}${fieldDefinition.name.substring(1)}", TypeUtils.Companion.getClass) val getterMethodBuilder = MethodSpec.methodBuilder(getterName).addModifiers(Modifier.PUBLIC).returns(returnType).addStatement("return \$N", ReservedKeywordSanitizer.sanitize(fieldDefinition.name)) if (fieldDefinition.overrideGetter) { @@ -416,19 +416,36 @@ abstract class BaseDataTypeGenerator( getterMethodBuilder.addJavadoc(fieldDefinition.description.sanitizeJavaDoc()) } - javaType.addMethod(getterMethodBuilder.build()) - val setterName = typeUtils.transformIfDefaultClassMethodExists("set${fieldDefinition.name[0].uppercase()}${fieldDefinition.name.substring(1)}", TypeUtils.Companion.setClass) - javaType.addMethod( - MethodSpec.methodBuilder(setterName) - .addModifiers(Modifier.PUBLIC) - .addParameter(returnType, ReservedKeywordSanitizer.sanitize(fieldDefinition.name)) - .addStatement( - "this.\$N = \$N", - ReservedKeywordSanitizer.sanitize(fieldDefinition.name), - ReservedKeywordSanitizer.sanitize(fieldDefinition.name) - ).build() - ) + val parameterBuilder = ParameterSpec.builder(returnType, ReservedKeywordSanitizer.sanitize(fieldDefinition.name)) + val setterMethodBuilder = MethodSpec.methodBuilder(setterName) + .addModifiers(Modifier.PUBLIC) + .addStatement( + "this.\$N = \$N", + ReservedKeywordSanitizer.sanitize(fieldDefinition.name), + ReservedKeywordSanitizer.sanitize(fieldDefinition.name) + ) + + if (fieldDefinition.directives.isNotEmpty()) { + val (annotations, comments) = applyDirectives(fieldDefinition.directives) + if (!comments.isNullOrBlank()) { + fieldBuilder.addJavadoc("\$L", comments) + } + annotations.forEach { entry -> + when (SiteTarget.valueOf(entry.key)) { + SiteTarget.FIELD -> fieldBuilder.addAnnotations(annotations[SiteTarget.FIELD.name]) + SiteTarget.GET -> getterMethodBuilder.addAnnotations(annotations[SiteTarget.GET.name]) + SiteTarget.SET -> setterMethodBuilder.addAnnotations(annotations[SiteTarget.SET.name]) + SiteTarget.SETPARAM -> parameterBuilder.addAnnotations(annotations[SiteTarget.SETPARAM.name]) + else -> fieldBuilder.addAnnotations(annotations[entry.key]) + } + } + } + setterMethodBuilder.addParameter(parameterBuilder.build()) + + javaType.addField(fieldBuilder.build()) + javaType.addMethod(getterMethodBuilder.build()) + javaType.addMethod(setterMethodBuilder.build()) } private fun addAbstractGetter(returnType: com.squareup.javapoet.TypeName?, fieldDefinition: Field, javaType: TypeSpec.Builder) { diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinPoetUtils.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinPoetUtils.kt index 1cdf6a85d..4e64f484e 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinPoetUtils.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinPoetUtils.kt @@ -287,6 +287,7 @@ private fun ktTypeClassBestGuess(name: String): ClassName { * name -> Name of the class to be annotated. It will contain className with oor without the package name (Mandatory) * type -> The type of operation intended with this annotation. This value is also used to look up if there is any default packages associated with this annotation in the config * inputs -> These are the input parameters needed for the annotation. If empty no inputs will be present for the annotation + * target -> The site target where the annotation should be applied. If no site target is present annotation will not contain any site targets */ fun customAnnotation(annotationArgumentMap: MutableMap>>, config: CodeGenConfig): AnnotationSpec { if (annotationArgumentMap.isEmpty() || !annotationArgumentMap.containsKey(ParserConstants.NAME) || annotationArgumentMap[ParserConstants.NAME] is NullValue || (annotationArgumentMap[ParserConstants.NAME] as StringValue).value.isEmpty()) { @@ -299,6 +300,9 @@ fun customAnnotation(annotationArgumentMap: MutableMap>>, ) val className = ClassName(packageName = packageName, simpleNames = listOf(simpleName)) val annotation: AnnotationSpec.Builder = AnnotationSpec.builder(className) + if (annotationArgumentMap.containsKey(ParserConstants.SITE_TARGET)) { + annotation.useSiteTarget(AnnotationSpec.UseSiteTarget.valueOf((annotationArgumentMap[ParserConstants.SITE_TARGET] as StringValue).value.uppercase())) + } if (annotationArgumentMap.containsKey(ParserConstants.INPUTS)) { val codeBlocks: List = parseInputs(config, annotationArgumentMap[ParserConstants.INPUTS] as ObjectValue, (annotationArgumentMap[ParserConstants.NAME] as StringValue).value) codeBlocks.forEach { codeBlock -> diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/ParserConstants.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/ParserConstants.kt index 41e0af26f..515ca07e8 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/ParserConstants.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/ParserConstants.kt @@ -30,4 +30,5 @@ object ParserConstants { const val MESSAGE = "message" const val REPLACE_WITH = "replaceWith" const val REPLACE_WITH_CLASS = "ReplaceWith" + const val SITE_TARGET = "target" } diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/SiteTarget.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/SiteTarget.kt new file mode 100644 index 000000000..f9026e7db --- /dev/null +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/SiteTarget.kt @@ -0,0 +1,32 @@ +/* + * + * 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. + * + */ + +package com.netflix.graphql.dgs.codegen.generators.shared + +enum class SiteTarget { + DEFAULT, + FILE, + PROPERTY, + FIELD, + GET, + SET, + RECEIVER, + PARAM, + SETPARAM, + DELEGATE; +} 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 50eda4c2b..c4417dfc5 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 @@ -3396,4 +3396,158 @@ It takes a title and such. assertThat(fields).hasSize(1) assertThat(fields[0].annotations).hasSize(0) } + + @Test + fun annotateOnTypesWithTargetsOnGet() { + val schema = """ + type Person @deprecated(reason: "This is going bye bye") @annotate(name: "ValidPerson", type: "validator", inputs: {types: [HUSBAND, WIFE]}) { + name: String @annotate(name: "com.test.anotherValidator.ValidName", target: "get") @annotate(name: "com.test.nullValidator.NullValue") + } + """.trimIndent() + + val (dataTypes) = CodeGen( + CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName, + includeImports = mapOf(Pair("validator", "com.test.validator")), + includeEnumImports = mapOf("ValidPerson" to mapOf("types" to "com.enums")), + generateCustomAnnotations = true + ) + ).generate() + + assertThat(dataTypes.size).isEqualTo(1) + val person = dataTypes.single().typeSpec + assertThat(person.name).isEqualTo("Person") + assertThat(person.annotations).hasSize(2) + val fields = person.fieldSpecs + assertThat(fields).hasSize(1) + assertThat(fields[0].annotations).hasSize(1) + val methods = person.methodSpecs + assertThat((methods[0] as MethodSpec).name).isEqualTo("getName") + assertThat(methods[0].annotations).hasSize(1) + assertThat(((methods[0].annotations[0] as AnnotationSpec).type as ClassName).simpleName()).isEqualTo("ValidName") + } + + @Test + fun annotateOnTypesWithTargetsOnField() { + val schema = """ + type Person @deprecated(reason: "This is going bye bye") @annotate(name: "ValidPerson", type: "validator", inputs: {types: [HUSBAND, WIFE]}) { + name: String @annotate(name: "com.test.anotherValidator.ValidName", target: "field") @annotate(name: "com.test.nullValidator.NullValue") + } + """.trimIndent() + + val (dataTypes) = CodeGen( + CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName, + includeImports = mapOf(Pair("validator", "com.test.validator")), + includeEnumImports = mapOf("ValidPerson" to mapOf("types" to "com.enums")), + generateCustomAnnotations = true + ) + ).generate() + + assertThat(dataTypes.size).isEqualTo(1) + val person = dataTypes.single().typeSpec + assertThat(person.name).isEqualTo("Person") + assertThat(person.annotations).hasSize(2) + val fields = person.fieldSpecs + assertThat(fields).hasSize(1) + assertThat(fields[0].annotations).hasSize(2) + assertThat(((fields[0].annotations[0] as AnnotationSpec).type as ClassName).simpleName()).isEqualTo("ValidName") + assertThat(((fields[0].annotations[0] as AnnotationSpec).type as ClassName).canonicalName()).isEqualTo("com.test.anotherValidator.ValidName") + assertThat(((fields[0].annotations[1] as AnnotationSpec).type as ClassName).simpleName()).isEqualTo("NullValue") + assertThat(((fields[0].annotations[1] as AnnotationSpec).type as ClassName).canonicalName()).isEqualTo("com.test.nullValidator.NullValue") + val methods = person.methodSpecs + assertThat((methods[0] as MethodSpec).name).isEqualTo("getName") + assertThat(methods[0].annotations).hasSize(0) + } + + @Test + fun annotateOnTypesWithTargetsOnSet() { + val schema = """ + type Person @deprecated(reason: "This is going bye bye") @annotate(name: "ValidPerson", type: "validator", inputs: {types: [HUSBAND, WIFE]}) { + name: String @annotate(name: "com.test.anotherValidator.ValidName", target: "set") @annotate(name: "com.test.nullValidator.NullValue") + } + """.trimIndent() + + val (dataTypes) = CodeGen( + CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName, + includeImports = mapOf(Pair("validator", "com.test.validator")), + includeEnumImports = mapOf("ValidPerson" to mapOf("types" to "com.enums")), + generateCustomAnnotations = true + ) + ).generate() + + assertThat(dataTypes.size).isEqualTo(1) + val person = dataTypes.single().typeSpec + assertThat(person.name).isEqualTo("Person") + assertThat(person.annotations).hasSize(2) + val fields = person.fieldSpecs + assertThat(fields).hasSize(1) + assertThat(fields[0].annotations).hasSize(1) + val methods = person.methodSpecs + assertThat((methods[0] as MethodSpec).name).isEqualTo("getName") + assertThat(methods[0].annotations).hasSize(0) + assertThat((methods[1] as MethodSpec).name).isEqualTo("setName") + assertThat(methods[1].annotations).hasSize(1) + assertThat(((methods[1].annotations[0] as AnnotationSpec).type as ClassName).simpleName()).isEqualTo("ValidName") + } + + @Test + fun annotateOnTypesWithTargetsOnSetParam() { + val schema = """ + type Person @deprecated(reason: "This is going bye bye") @annotate(name: "ValidPerson", type: "validator", inputs: {types: [HUSBAND, WIFE]}) { + name: String @annotate(name: "com.test.anotherValidator.ValidName", target: "setparam") @annotate(name: "com.test.nullValidator.NullValue") + } + """.trimIndent() + + val (dataTypes) = CodeGen( + CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName, + includeImports = mapOf(Pair("validator", "com.test.validator")), + includeEnumImports = mapOf("ValidPerson" to mapOf("types" to "com.enums")), + generateCustomAnnotations = true + ) + ).generate() + + assertThat(dataTypes.size).isEqualTo(1) + val person = dataTypes.single().typeSpec + assertThat(person.name).isEqualTo("Person") + assertThat(person.annotations).hasSize(2) + val fields = person.fieldSpecs + assertThat(fields).hasSize(1) + assertThat(fields[0].annotations).hasSize(1) + val methods = person.methodSpecs + assertThat((methods[0] as MethodSpec).name).isEqualTo("getName") + assertThat(methods[0].annotations).hasSize(0) + assertThat((methods[1] as MethodSpec).name).isEqualTo("setName") + assertThat(methods[1].annotations).hasSize(0) + val parameters = (methods[1] as MethodSpec).parameters + assertThat(parameters).hasSize(1) + assertThat(((parameters[0].annotations[0] as AnnotationSpec).type as ClassName).simpleName()).isEqualTo("ValidName") + } + + @Test + fun annotateOnTypesWithTargetsOnInvalidTarget() { + val schema = """ + type Person @deprecated(reason: "This is going bye bye") @annotate(name: "ValidPerson", type: "validator", inputs: {types: [HUSBAND, WIFE]}) { + name: String @annotate(name: "com.test.anotherValidator.ValidName", target: "invalid") @annotate(name: "com.test.nullValidator.NullValue") + } + """.trimIndent() + + assertThrows { + CodeGen( + CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName, + includeImports = mapOf(Pair("validator", "com.test.validator")), + includeEnumImports = mapOf("ValidPerson" to mapOf("types" to "com.enums")), + generateCustomAnnotations = true + ) + ).generate() + } + } } 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 6eb44ea91..176d2d6e6 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 @@ -2285,6 +2285,68 @@ class KotlinCodeGenTest { assertThat((parameterSpec.annotations[2].typeName as ClassName).canonicalName).isEqualTo("com.test.nullValidator.NullValue") } + @Test + fun annotateOnTypesWithTarget() { + val schema = """ + type Person @annotate(name: "ValidPerson", type: "validator", inputs: {types: [HUSBAND, WIFE]}) { + name: String @annotate(name: "com.test.anotherValidator.ValidName", target: "field") @annotate(name: "com.test.nullValidator.NullValue") + } + """.trimIndent() + + val dataTypes = CodeGen( + CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName, + language = Language.KOTLIN, + includeImports = mapOf(Pair("validator", "com.test.validator"), Pair("types", "com.enums")), + includeEnumImports = mapOf( + "ValidPerson" to mapOf(Pair("types", "com.enums")) + ), + generateCustomAnnotations = true + ) + ).generate().kotlinDataTypes + + assertThat(dataTypes).hasSize(1) + assertThat(dataTypes[0].name).isEqualTo("Person") + + val annotationSpec = (((dataTypes as ArrayList<*>)[0] as FileSpec).members[0] as TypeSpec).annotationSpecs[0] + assertThat((annotationSpec.typeName as ClassName).canonicalName).isEqualTo("com.test.validator.ValidPerson") + assertThat(annotationSpec.members[0]).extracting("args").asList().hasSize(1) + assertThat(annotationSpec.members[0]).extracting("args").asString().contains("com.enums.HUSBAND", "com.enums.WIFE") + + val parameterSpec = (((dataTypes[0].members)[0] as TypeSpec).primaryConstructor as FunSpec).parameters[0] + assertThat(parameterSpec.name).isEqualTo("name") + assertThat(parameterSpec.annotations).hasSize(3) + assertThat((parameterSpec.annotations[0].typeName as ClassName).canonicalName).isEqualTo("com.fasterxml.jackson.annotation.JsonProperty") + assertThat((parameterSpec.annotations[1].typeName as ClassName).canonicalName).isEqualTo("com.test.anotherValidator.ValidName") + assertThat((parameterSpec.annotations[1].useSiteTarget as AnnotationSpec.UseSiteTarget).name).isEqualTo("FIELD") + assertThat((parameterSpec.annotations[2].typeName as ClassName).canonicalName).isEqualTo("com.test.nullValidator.NullValue") + } + + @Test + fun annotateOnTypesWithInvalidTarget() { + val schema = """ + type Person @annotate(name: "ValidPerson", type: "validator", inputs: {types: [HUSBAND, WIFE]}) { + name: String @annotate(name: "com.test.anotherValidator.ValidName", target: "invalid") @annotate(name: "com.test.nullValidator.NullValue") + } + """.trimIndent() + + assertThrows { + CodeGen( + CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName, + language = Language.KOTLIN, + includeImports = mapOf(Pair("validator", "com.test.validator"), Pair("types", "com.enums")), + includeEnumImports = mapOf( + "ValidPerson" to mapOf(Pair("types", "com.enums")) + ), + generateCustomAnnotations = true + ) + ).generate() + } + } + @Test fun annotateOnTypesWithoutName() { val schema = """ From f1a0c173f88b7956e31f47ce40892597c36563d8 Mon Sep 17 00:00:00 2001 From: Lakshmi Vijayachandran Date: Fri, 14 Oct 2022 15:39:06 -0700 Subject: [PATCH 2/5] Fixed merge error --- .../graphql/dgs/codegen/generators/java/DataTypeGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8ebf97188..3dfa5ef52 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 @@ -200,7 +200,7 @@ abstract class BaseDataTypeGenerator( } } if (directive.name == ParserConstants.DEPRECATED && config.addDeprecatedAnnotation) { - annotations.add(deprecatedAnnotation()) + annotations[siteTarget] = mutableListOf(deprecatedAnnotation()) if (argumentMap.containsKey(ParserConstants.REASON)) { val reason: String = (argumentMap[ParserConstants.REASON] as StringValue).value val replace = reason.substringAfter(ParserConstants.REPLACE_WITH_STR, "") From 334d8feed7cbeb941092df1cade4e390f797530f Mon Sep 17 00:00:00 2001 From: Lakshmi Vijayachandran Date: Fri, 14 Oct 2022 15:53:16 -0700 Subject: [PATCH 3/5] Fixed merge errors due to deprecation config --- .../netflix/graphql/dgs/codegen/CodeGenTest.kt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) 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 382d00af1..5a8020801 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 @@ -3566,7 +3566,8 @@ It takes a title and such. packageName = basePackageName, includeImports = mapOf(Pair("validator", "com.test.validator")), includeEnumImports = mapOf("ValidPerson" to mapOf("types" to "com.enums")), - generateCustomAnnotations = true + generateCustomAnnotations = true, + addDeprecatedAnnotation = true ) ).generate() @@ -3597,7 +3598,8 @@ It takes a title and such. packageName = basePackageName, includeImports = mapOf(Pair("validator", "com.test.validator")), includeEnumImports = mapOf("ValidPerson" to mapOf("types" to "com.enums")), - generateCustomAnnotations = true + generateCustomAnnotations = true, + addDeprecatedAnnotation = true ) ).generate() @@ -3631,7 +3633,8 @@ It takes a title and such. packageName = basePackageName, includeImports = mapOf(Pair("validator", "com.test.validator")), includeEnumImports = mapOf("ValidPerson" to mapOf("types" to "com.enums")), - generateCustomAnnotations = true + generateCustomAnnotations = true, + addDeprecatedAnnotation = true ) ).generate() @@ -3664,7 +3667,8 @@ It takes a title and such. packageName = basePackageName, includeImports = mapOf(Pair("validator", "com.test.validator")), includeEnumImports = mapOf("ValidPerson" to mapOf("types" to "com.enums")), - generateCustomAnnotations = true + generateCustomAnnotations = true, + addDeprecatedAnnotation = true ) ).generate() @@ -3700,7 +3704,8 @@ It takes a title and such. packageName = basePackageName, includeImports = mapOf(Pair("validator", "com.test.validator")), includeEnumImports = mapOf("ValidPerson" to mapOf("types" to "com.enums")), - generateCustomAnnotations = true + generateCustomAnnotations = true, + addDeprecatedAnnotation = true ) ).generate() } From 0e24af95034d8a08695e2edb01111b6c7020a429 Mon Sep 17 00:00:00 2001 From: Lakshmi Vijayachandran Date: Tue, 25 Oct 2022 08:50:01 -0700 Subject: [PATCH 4/5] IIEA-10932 Added support for param directive --- .../generators/java/DataTypeGenerator.kt | 14 ++++++- .../graphql/dgs/codegen/CodeGenTest.kt | 38 +++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) 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 3dfa5ef52..d01a0b31a 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 @@ -371,8 +371,17 @@ abstract class BaseDataTypeGenerator( private fun addParameterizedConstructor(fieldDefinitions: List, javaType: TypeSpec.Builder) { val constructorBuilder = MethodSpec.constructorBuilder() fieldDefinitions.forEach { + val parameterBuilder = ParameterSpec.builder(it.type, ReservedKeywordSanitizer.sanitize(it.name)) + if (it.directives.isNotEmpty()) { + val (annotations, comments) = applyDirectives(it.directives) + annotations.forEach { entry -> + if (SiteTarget.valueOf(entry.key) == SiteTarget.PARAM) { + parameterBuilder.addAnnotations(annotations[SiteTarget.PARAM.name]) + } + } + } constructorBuilder - .addParameter(it.type, ReservedKeywordSanitizer.sanitize(it.name)) + .addParameter(parameterBuilder.build()) .addModifiers(Modifier.PUBLIC) .addStatement("this.\$N = \$N", ReservedKeywordSanitizer.sanitize(it.name), ReservedKeywordSanitizer.sanitize(it.name)) } @@ -431,12 +440,13 @@ abstract class BaseDataTypeGenerator( if (!comments.isNullOrBlank()) { fieldBuilder.addJavadoc("\$L", comments) } - annotations.forEach { entry -> + for (entry in annotations) { when (SiteTarget.valueOf(entry.key)) { SiteTarget.FIELD -> fieldBuilder.addAnnotations(annotations[SiteTarget.FIELD.name]) SiteTarget.GET -> getterMethodBuilder.addAnnotations(annotations[SiteTarget.GET.name]) SiteTarget.SET -> setterMethodBuilder.addAnnotations(annotations[SiteTarget.SET.name]) SiteTarget.SETPARAM -> parameterBuilder.addAnnotations(annotations[SiteTarget.SETPARAM.name]) + SiteTarget.PARAM -> continue else -> fieldBuilder.addAnnotations(annotations[entry.key]) } } 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 5a8020801..caa0d70f5 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 @@ -3689,6 +3689,44 @@ It takes a title and such. assertThat(((parameters[0].annotations[0] as AnnotationSpec).type as ClassName).simpleName()).isEqualTo("ValidName") } + @Test + fun annotateOnTypesWithTargetsOnParam() { + val schema = """ + type Person @deprecated(reason: "This is going bye bye") @annotate(name: "ValidPerson", type: "validator", inputs: {types: [HUSBAND, WIFE]}) { + name: String @annotate(name: "com.test.anotherValidator.ValidName", target: "param") @annotate(name: "com.test.nullValidator.NullValue") + } + """.trimIndent() + + val (dataTypes) = CodeGen( + CodeGenConfig( + schemas = setOf(schema), + packageName = basePackageName, + includeImports = mapOf(Pair("validator", "com.test.validator")), + includeEnumImports = mapOf("ValidPerson" to mapOf("types" to "com.enums")), + generateCustomAnnotations = true, + addDeprecatedAnnotation = true + ) + ).generate() + + assertThat(dataTypes.size).isEqualTo(1) + val person = dataTypes.single().typeSpec + assertThat(person.name).isEqualTo("Person") + assertThat(person.annotations).hasSize(2) + val fields = person.fieldSpecs + assertThat(fields).hasSize(1) + assertThat(fields[0].annotations).hasSize(1) + val methods = person.methodSpecs + assertThat((methods[0] as MethodSpec).name).isEqualTo("getName") + assertThat(methods[0].annotations).hasSize(0) + assertThat((methods[1] as MethodSpec).name).isEqualTo("setName") + assertThat(methods[1].annotations).hasSize(0) + assertThat((methods[3] as MethodSpec).name).isEqualTo("") + assertThat(methods[3].annotations).hasSize(0) + val parameters = (methods[3] as MethodSpec).parameters + assertThat(parameters).hasSize(1) + assertThat(((parameters[0].annotations[0] as AnnotationSpec).type as ClassName).simpleName()).isEqualTo("ValidName") + } + @Test fun annotateOnTypesWithTargetsOnInvalidTarget() { val schema = """ From 4764e5b40ce68adceb237ebe623631a5860691d6 Mon Sep 17 00:00:00 2001 From: Lakshmi Vijayachandran Date: Tue, 25 Oct 2022 09:27:07 -0700 Subject: [PATCH 5/5] IIEA-10932 Updated the link for site targets --- .../netflix/graphql/dgs/codegen/generators/shared/SiteTarget.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/SiteTarget.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/SiteTarget.kt index f9026e7db..0f2d291bd 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/SiteTarget.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/shared/SiteTarget.kt @@ -18,6 +18,7 @@ package com.netflix.graphql.dgs.codegen.generators.shared +// The site targets as defined https://kotlinlang.org/docs/annotations.html#annotation-use-site-targets. enum class SiteTarget { DEFAULT, FILE,