From 600c902c562a7e463422e5800b9c95c56bd296a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=A6=E5=A2=83=E8=BF=B7=E7=A6=BB?= <568845948@qq.com> Date: Thu, 25 Feb 2021 22:07:34 +0800 Subject: [PATCH] Fix Scala and Kotlin minor code generation issues (#558) * Optimize template * add test --- .../codegen/scala/ScalaDataModelMapper.java | 6 +++ .../kotlin-lang/kotlinClassGraphqlType.ftl | 8 ++-- .../kotlin/GraphQLCodegenNullableTest.java | 23 +++++++++++- .../scala/GraphQLCodegenExtendTest.java | 30 +++++++++++++-- .../GraphQLCodegenReactorToStringTest.java | 28 ++++++++++++++ .../InterfaceWithOptionalField.kt.txt | 9 +++++ .../kt/optional/TypeWithMandatoryField.kt.txt | 36 ++++++++++++++++++ .../InterfaceWithOptionalField.scala.txt | 9 +++++ .../optional/TypeWithMandatoryField.scala.txt | 34 +++++++++++++++++ .../scala/tostring/Synchronized.scala.txt | 12 +++--- .../tostring/TOSTRING_Synchronized.scala.txt | 37 +++++++++++++++++++ 11 files changed, 217 insertions(+), 15 deletions(-) create mode 100644 src/test/resources/expected-classes/kt/optional/InterfaceWithOptionalField.kt.txt create mode 100644 src/test/resources/expected-classes/kt/optional/TypeWithMandatoryField.kt.txt create mode 100644 src/test/resources/expected-classes/scala/optional/InterfaceWithOptionalField.scala.txt create mode 100644 src/test/resources/expected-classes/scala/optional/TypeWithMandatoryField.scala.txt create mode 100644 src/test/resources/expected-classes/scala/tostring/TOSTRING_Synchronized.scala.txt diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/scala/ScalaDataModelMapper.java b/src/main/java/com/kobylynskyi/graphql/codegen/scala/ScalaDataModelMapper.java index 62252904..2fef593c 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/scala/ScalaDataModelMapper.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/scala/ScalaDataModelMapper.java @@ -31,6 +31,12 @@ public class ScalaDataModelMapper implements DataModelMapper { if (SCALA_RESTRICTED_KEYWORDS.contains(fieldName)) { return wrapString(fieldName, RESTRICTED_WORDS_WRAP_WITH); } + + // Scala case class's Fields cannot also use the names of these methods. + if (SCALA_RESTRICTED_METHOD_NAMES.contains(fieldName)) { + return Utils.capitalize(fieldName); + } + return fieldName; } diff --git a/src/main/resources/templates/kotlin-lang/kotlinClassGraphqlType.ftl b/src/main/resources/templates/kotlin-lang/kotlinClassGraphqlType.ftl index cdef5884..cfb3a54e 100755 --- a/src/main/resources/templates/kotlin-lang/kotlinClassGraphqlType.ftl +++ b/src/main/resources/templates/kotlin-lang/kotlinClassGraphqlType.ftl @@ -91,9 +91,9 @@ open class ${className}()<#if implements?has_content> : <#list implements as int joiner.add("${field.originalName}: " + GraphQLRequestSerializer.getEntry(${field.name})) <#else> <#if field.type == "String?"> - joiner.add("${field.originalName}: \"${field.name}\"") + joiner.add("${field.originalName}: \"" + ${field.name} + "\""); <#else> - joiner.add(${field.originalName}: ${field.name}") + joiner.add("${field.originalName}: " + ${field.name}); } @@ -102,9 +102,9 @@ open class ${className}()<#if implements?has_content> : <#list implements as int joiner.add("${field.originalName}: " + GraphQLRequestSerializer.getEntry(${field.name})) <#else> <#if field.type == "String"> - joiner.add("${field.originalName}: \"${field.name}\"") + joiner.add("${field.originalName}: \"" + ${field.name} + "\""); <#else> - joiner.add(${field.originalName}: ${field.name}") + joiner.add("${field.originalName}: " + ${field.name}); diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/kotlin/GraphQLCodegenNullableTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/kotlin/GraphQLCodegenNullableTest.java index 54421967..2c6e3e2a 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/kotlin/GraphQLCodegenNullableTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/kotlin/GraphQLCodegenNullableTest.java @@ -85,4 +85,25 @@ class GraphQLCodegenNullableTest { new File("src/test/resources/expected-classes/kt/nullable/QueryResolver_WITH_Prefix_Suffix.kt.txt"), getFileByName(files, "QueryResolver.kt")); } -} \ No newline at end of file + + /** + * Verify Int to override Int? + */ + @Test + void generate_OptionalFieldInInterfaceAndMandatoryInType() throws Exception { + mappingConfig.setGenerateBuilder(true); + mappingConfig.setGenerateToString(true); + mappingConfig.setGenerateEqualsAndHashCode(true); + schemaFinder.setIncludePattern("optional-vs-mandatory-types.graphqls"); + + new KotlinGraphQLCodegen(schemaFinder.findSchemas(), outputBuildDir, mappingConfig, TestUtils.getStaticGeneratedInfo()) + .generate(); + + File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); + + assertSameTrimmedContent(new File("src/test/resources/expected-classes/kt/optional/InterfaceWithOptionalField.kt.txt"), + getFileByName(files, "InterfaceWithOptionalField.kt")); + assertSameTrimmedContent(new File("src/test/resources/expected-classes/kt/optional/TypeWithMandatoryField.kt.txt"), + getFileByName(files, "TypeWithMandatoryField.kt")); + } +} diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/scala/GraphQLCodegenExtendTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/scala/GraphQLCodegenExtendTest.java index ea5be160..52b680ed 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/scala/GraphQLCodegenExtendTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/scala/GraphQLCodegenExtendTest.java @@ -11,10 +11,7 @@ import org.junit.jupiter.api.Test; import java.io.File; import java.nio.file.Paths; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; +import java.util.*; import static com.kobylynskyi.graphql.codegen.TestUtils.assertSameTrimmedContent; import static com.kobylynskyi.graphql.codegen.TestUtils.getFileByName; @@ -217,4 +214,29 @@ class GraphQLCodegenExtendTest { new File("src/test/resources/expected-classes/scala/extend/nullable/QueryResolver.scala.txt"), getFileByName(files, "QueryResolver.scala")); } + + /** + * Verify Int! to override Int in graphql. + * In scala, Int type cannot be null, So, option Int is Option[Int]. Can not override from Option[Int] to Int. + */ + @Test + void generate_OptionalFieldInInterfaceAndMandatoryInType() throws Exception { + mappingConfig.setGenerateBuilder(true); + mappingConfig.setGenerateToString(true); + mappingConfig.setGenerateEqualsAndHashCode(true); + Map maps = new HashMap<>(); + maps.put("Int", "Int");// Now, That's the only way to do it. + mappingConfig.setCustomTypesMapping(maps); + schemaFinder.setIncludePattern("optional-vs-mandatory-types.graphqls"); + + new ScalaGraphQLCodegen(schemaFinder.findSchemas(), outputBuildDir, mappingConfig, TestUtils.getStaticGeneratedInfo()) + .generate(); + + File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); + + assertSameTrimmedContent(new File("src/test/resources/expected-classes/scala/optional/InterfaceWithOptionalField.scala.txt"), + getFileByName(files, "InterfaceWithOptionalField.scala")); + assertSameTrimmedContent(new File("src/test/resources/expected-classes/scala/optional/TypeWithMandatoryField.scala.txt"), + getFileByName(files, "TypeWithMandatoryField.scala")); + } } \ No newline at end of file diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/scala/GraphQLCodegenReactorToStringTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/scala/GraphQLCodegenReactorToStringTest.java index 42016d81..f68bbd4d 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/scala/GraphQLCodegenReactorToStringTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/scala/GraphQLCodegenReactorToStringTest.java @@ -87,4 +87,32 @@ class GraphQLCodegenReactorToStringTest { } } + @Test + void generate_SetGenerateClient_False() throws Exception { + mappingConfig.setPackageName("com.kobylynskyi.graphql.codegen.prot"); + mappingConfig.setGenerateEqualsAndHashCode(true); + mappingConfig.setGenerateClient(false); + mappingConfig.setGenerateToString(true); + mappingConfig.setUseObjectMapperForRequestSerialization(singleton("TestEnum")); + mappingConfig.putCustomTypeMappingIfAbsent("DateTime", "java.time.ZonedDateTime"); + mappingConfig.setGenerateApis(true); + mappingConfig.setGenerateModelsForRootTypes(true); + mappingConfig.setApiNameSuffix("API"); + + new ScalaGraphQLCodegen(singletonList("src/test/resources/schemas/scala/restricted-words.graphqls"), + outputBuildDir, mappingConfig, TestUtils.getStaticGeneratedInfo()).generate(); + + File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); + List generatedFileNames = Arrays.stream(files).map(File::getName).filter(f -> Objects.equals("Synchronized.scala", f)).sorted().collect(toList()); + assertEquals(singletonList("Synchronized.scala"), generatedFileNames); + + for (File file : files) { + if (Objects.equals("Synchronized.scala", file.getName())) { + assertSameTrimmedContent( + new File(String.format("src/test/resources/expected-classes/scala/tostring/%s.txt", "TOSTRING_Synchronized.scala")), + file); + } + } + } + } diff --git a/src/test/resources/expected-classes/kt/optional/InterfaceWithOptionalField.kt.txt b/src/test/resources/expected-classes/kt/optional/InterfaceWithOptionalField.kt.txt new file mode 100644 index 00000000..8ff70f10 --- /dev/null +++ b/src/test/resources/expected-classes/kt/optional/InterfaceWithOptionalField.kt.txt @@ -0,0 +1,9 @@ +@javax.annotation.Generated( + value = ["com.kobylynskyi.graphql.codegen.GraphQLCodegen"], + date = "2020-12-31T23:59:59-0500" +) +interface InterfaceWithOptionalField { + + val test: Int? + +} \ No newline at end of file diff --git a/src/test/resources/expected-classes/kt/optional/TypeWithMandatoryField.kt.txt b/src/test/resources/expected-classes/kt/optional/TypeWithMandatoryField.kt.txt new file mode 100644 index 00000000..95ee51bf --- /dev/null +++ b/src/test/resources/expected-classes/kt/optional/TypeWithMandatoryField.kt.txt @@ -0,0 +1,36 @@ +import java.util.StringJoiner + +@javax.annotation.Generated( + value = ["com.kobylynskyi.graphql.codegen.GraphQLCodegen"], + date = "2020-12-31T23:59:59-0500" +) +data class TypeWithMandatoryField( + override + val test: Int +) : InterfaceWithOptionalField { + + companion object { + fun builder(): Builder = Builder() + } + + // In the future, it maybe change. + override fun toString(): String { + val joiner = StringJoiner(", ", "{ ", " }") + joiner.add("test: " + test); + return joiner.toString() + } + + class Builder { + + private var test: Int = 0 + + fun setTest(test: Int): Builder { + this.test = test + return this + } + + fun build(): TypeWithMandatoryField { + return TypeWithMandatoryField(test) + } + } +} \ No newline at end of file diff --git a/src/test/resources/expected-classes/scala/optional/InterfaceWithOptionalField.scala.txt b/src/test/resources/expected-classes/scala/optional/InterfaceWithOptionalField.scala.txt new file mode 100644 index 00000000..cddf4f04 --- /dev/null +++ b/src/test/resources/expected-classes/scala/optional/InterfaceWithOptionalField.scala.txt @@ -0,0 +1,9 @@ +@javax.annotation.Generated( + value = Array("com.kobylynskyi.graphql.codegen.GraphQLCodegen"), + date = "2020-12-31T23:59:59-0500" +) +trait InterfaceWithOptionalField { + + val test: Int + +} \ No newline at end of file diff --git a/src/test/resources/expected-classes/scala/optional/TypeWithMandatoryField.scala.txt b/src/test/resources/expected-classes/scala/optional/TypeWithMandatoryField.scala.txt new file mode 100644 index 00000000..9bdc7a2b --- /dev/null +++ b/src/test/resources/expected-classes/scala/optional/TypeWithMandatoryField.scala.txt @@ -0,0 +1,34 @@ +import scala.collection.JavaConverters._ + +@javax.annotation.Generated( + value = Array("com.kobylynskyi.graphql.codegen.GraphQLCodegen"), + date = "2020-12-31T23:59:59-0500" +) +case class TypeWithMandatoryField( + override val test: Int +) extends InterfaceWithOptionalField { + + override def toString(): String = { + Seq( + "test: " + test + ).filter(_ != "").mkString("{", ",", "}") + } +} + +object TypeWithMandatoryField { + + def builder(): TypeWithMandatoryField.Builder = new Builder() + + class Builder { + + private var test: Int = _ + + def setTest(test: Int): Builder = { + this.test = test + this + } + + def build(): TypeWithMandatoryField = TypeWithMandatoryField(test) + + } +} \ No newline at end of file diff --git a/src/test/resources/expected-classes/scala/tostring/Synchronized.scala.txt b/src/test/resources/expected-classes/scala/tostring/Synchronized.scala.txt index 2e9fa7cd..9b86a562 100644 --- a/src/test/resources/expected-classes/scala/tostring/Synchronized.scala.txt +++ b/src/test/resources/expected-classes/scala/tostring/Synchronized.scala.txt @@ -10,7 +10,7 @@ import TestEnum._ ) case class Synchronized( void: String, - wait: Char, + Wait: Char, `this`: Char, `super`: Char, `private`: Char, @@ -24,7 +24,7 @@ case class Synchronized( override def toString(): String = { Seq( if (void != null) "void: " + GraphQLRequestSerializer.getEntry(void) else "", - "wait: " + GraphQLRequestSerializer.getEntry(wait), + "wait: " + GraphQLRequestSerializer.getEntry(Wait), "this: " + GraphQLRequestSerializer.getEntry(`this`), "super: " + GraphQLRequestSerializer.getEntry(`super`), "private: " + GraphQLRequestSerializer.getEntry(`private`), @@ -44,7 +44,7 @@ object Synchronized { class Builder { private var void: String = _ - private var wait: Char = _ + private var Wait: Char = _ private var `this`: Char = _ private var `super`: Char = _ private var `private`: Char = _ @@ -59,8 +59,8 @@ object Synchronized { this } - def setWait(wait: Char): Builder = { - this.wait = wait + def setWait(Wait: Char): Builder = { + this.Wait = Wait this } @@ -104,7 +104,7 @@ object Synchronized { this } - def build(): Synchronized = Synchronized(void, wait, `this`, `super`, `private`, native, that, enum, Synchronized, date) + def build(): Synchronized = Synchronized(void, Wait, `this`, `super`, `private`, native, that, enum, Synchronized, date) } } \ No newline at end of file diff --git a/src/test/resources/expected-classes/scala/tostring/TOSTRING_Synchronized.scala.txt b/src/test/resources/expected-classes/scala/tostring/TOSTRING_Synchronized.scala.txt new file mode 100644 index 00000000..e9f961bc --- /dev/null +++ b/src/test/resources/expected-classes/scala/tostring/TOSTRING_Synchronized.scala.txt @@ -0,0 +1,37 @@ +package com.kobylynskyi.graphql.codegen.prot + +import scala.collection.JavaConverters._ +import TestEnum._ + +@javax.annotation.Generated( + value = Array("com.kobylynskyi.graphql.codegen.GraphQLCodegen"), + date = "2020-12-31T23:59:59-0500" +) +case class Synchronized( + void: String, + Wait: Char, + `this`: Char, + `super`: Char, + `private`: Char, + native: Char, + that: Char, + enum: TestEnum, + Synchronized: Synchronized, + date: java.time.ZonedDateTime +) { + + override def toString(): String = { + Seq( + if (void != null) "void: \"void\"" else "", + "wait: " + Wait, + "this: " + `this`, + "super: " + `super`, + "private: " + `private`, + "native: " + native, + "that: " + that, + if (enum != null) "enum: enum" else "", + if (Synchronized != null) "Synchronized: Synchronized" else "", + if (date != null) "date: date" else "" + ).filter(_ != "").mkString("{", ",", "}") + } +} \ No newline at end of file -- GitLab