From 13db38381be044ecf2712851fa5aa9f2d844cbcb Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 17 Mar 2023 20:04:19 +1300 Subject: [PATCH 01/10] Made possible to use custom templates --- .gitignore | 5 +++- .../graphql/codegen/GraphQLCodegenMojo.java | 10 +++++++ .../FreeMarkerTemplateFilesCreator.java | 8 ++++- .../FreeMarkerTemplatesRegistry.java | 12 ++++++-- .../model/GraphQLCodegenConfiguration.java | 8 +++++ .../graphql/codegen/model/MappingConfig.java | 30 +++++++++++++++++-- .../graphql/codegen/model/MappingContext.java | 6 ++++ .../GraphQLCodegenAnnotationsTest.java | 11 +++++++ src/test/resources/template/record_type.ftl | 19 ++++++++++++ 9 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 src/test/resources/template/record_type.ftl diff --git a/.gitignore b/.gitignore index 377246b2f..963d0847c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,10 @@ build modules.xml .idea/misc.xml *.ipr - +bin/ +.classpath +.project +.settings/ ### Maven ### target/ diff --git a/plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java b/plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java index 18af6a2a1..9c3ded048 100644 --- a/plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java +++ b/plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java @@ -1,6 +1,7 @@ package io.github.kobylynskyi.graphql.codegen; import com.kobylynskyi.graphql.codegen.GraphQLCodegen; +import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType; import com.kobylynskyi.graphql.codegen.java.JavaGraphQLCodegen; import com.kobylynskyi.graphql.codegen.kotlin.KotlinGraphQLCodegen; import com.kobylynskyi.graphql.codegen.model.ApiInterfaceStrategy; @@ -65,6 +66,9 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo @Parameter private Map customAnnotationsMapping; + @Parameter + private Map customTemplates; + @Parameter private Map directiveAnnotationsMapping; @@ -246,6 +250,7 @@ public void execute() throws MojoExecutionException { MappingConfig mappingConfig = new MappingConfig(); mappingConfig.setPackageName(packageName); mappingConfig.setCustomTypesMapping(convertToMap(customTypesMapping)); + mappingConfig.setCustomTemplates(customTemplates); mappingConfig.setCustomAnnotationsMapping(convertToListsMap(customAnnotationsMapping)); mappingConfig.setDirectiveAnnotationsMapping(convertToListsMap(directiveAnnotationsMapping)); mappingConfig.setApiNameSuffix(apiNameSuffix); @@ -737,4 +742,9 @@ private static Map convertToMap(Properties properties) { return result; } + @Override + public Map getCustomTemplates() { + return customTemplates; + } + } diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java b/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java index 96049c639..69de8ee29 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java @@ -48,7 +48,13 @@ public static File create(MappingContext mappingContext, } try (FileWriter fileWriter = new FileWriter(javaSourceFile)) { - Template template = FreeMarkerTemplatesRegistry.getTemplateWithLang(language, templateType); + Template template; + if (mappingContext.getCustomTemplates().containsKey(templateType)) { + template = FreeMarkerTemplatesRegistry.getCustomTemplates(mappingContext.getCustomTemplates().get(templateType)); + } else { + template = + FreeMarkerTemplatesRegistry.getTemplateWithLang(language, templateType); + } template.process(dataModel, fileWriter); } catch (Exception e) { throw new UnableToCreateFileException(e); diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplatesRegistry.java b/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplatesRegistry.java index 9d467641e..3c3da45d7 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplatesRegistry.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplatesRegistry.java @@ -22,9 +22,9 @@ class FreeMarkerTemplatesRegistry { private static final EnumMap> templateMap = new EnumMap<>(GeneratedLanguage.class); + private static final Configuration configuration = buildFreeMarkerTemplateConfiguration(); + static { - Configuration configuration = buildFreeMarkerTemplateConfiguration(); - try { templateMap.put(GeneratedLanguage.JAVA, getTemplates(configuration, GeneratedLanguage.JAVA)); templateMap.put(GeneratedLanguage.SCALA, getTemplates(configuration, GeneratedLanguage.SCALA)); @@ -70,4 +70,12 @@ private static Configuration buildFreeMarkerTemplateConfiguration() { return configuration; } + public static Template getCustomTemplates(String templatePath) { + try { + return configuration.getTemplate(templatePath); + } catch (IOException e) { + throw new UnableToLoadFreeMarkerTemplateException(e); + } + } + } diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java index 7972ca044..6a9894c57 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java @@ -1,5 +1,6 @@ package com.kobylynskyi.graphql.codegen.model; +import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType; import java.util.List; import java.util.Map; import java.util.Set; @@ -27,6 +28,13 @@ public interface GraphQLCodegenConfiguration { * @return mappings from GraphqlType to JavaType */ Map getCustomTypesMapping(); + + /** + * Can be used to supply custom template for code generation + * + * @return template to generate sources from + */ + Map getCustomTemplates(); /** * Can be used to supply custom annotations (serializers) for scalars. diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java index 72de287c0..b102cac7f 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java @@ -1,5 +1,7 @@ package com.kobylynskyi.graphql.codegen.model; +import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType; +import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -85,6 +87,7 @@ public class MappingConfig implements GraphQLCodegenConfiguration, Combinable parametrizedResolverAnnotations = new HashSet<>(); private Map customTypesMapping = new HashMap<>(); + private Map customTemplates = new HashMap<>(); private Set typesAsInterfaces = new HashSet<>(); @@ -94,9 +97,9 @@ public class MappingConfig implements GraphQLCodegenConfiguration, Combinable Map combineMap(Map thisMap, Map otherMap) { + private static Map combineMap(Map thisMap, Map otherMap) { if (thisMap != null && otherMap != null) { - Map resultMap = new HashMap<>(); + Map resultMap = new HashMap<>(); resultMap.putAll(thisMap); resultMap.putAll(otherMap); return resultMap; @@ -186,6 +189,7 @@ public void combine(MappingConfig source) { fieldsWithResolvers = combineSet(fieldsWithResolvers, source.fieldsWithResolvers); fieldsWithoutResolvers = combineSet(fieldsWithoutResolvers, source.fieldsWithoutResolvers); customTypesMapping = combineMap(customTypesMapping, source.customTypesMapping); + customTemplates = combineMap(customTemplates, source.customTemplates); customAnnotationsMapping = combineMap(customAnnotationsMapping, source.customAnnotationsMapping); directiveAnnotationsMapping = combineMap(directiveAnnotationsMapping, source.directiveAnnotationsMapping); resolverArgumentAnnotations = combineSet(resolverArgumentAnnotations, source.resolverArgumentAnnotations); @@ -244,6 +248,28 @@ public void setCustomTypesMapping(Map customTypesMapping) { this.customTypesMapping = customTypesMapping; } + /** + * Put custom template if absent. + * + * @param from the from + * @param to the to + */ + public void putCustomTemplatesIfAbsent(FreeMarkerTemplateType from, String to) { + if (customTemplates == null) { + customTemplates = new HashMap<>(); + } + customTemplates.computeIfAbsent(from, k -> to); + } + + @Override + public Map getCustomTemplates() { + return customTemplates; + } + + public void setCustomTemplates(Map customTemplates) { + this.customTemplates = customTemplates; + } + @Override public Map> getCustomAnnotationsMapping() { return customAnnotationsMapping; diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java index 6420a8158..d929cc317 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java @@ -1,5 +1,6 @@ package com.kobylynskyi.graphql.codegen.model; +import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType; import com.kobylynskyi.graphql.codegen.mapper.DataModelMapper; import com.kobylynskyi.graphql.codegen.mapper.DataModelMapperFactory; import com.kobylynskyi.graphql.codegen.mapper.FieldDefinitionToParameterMapper; @@ -83,6 +84,11 @@ public Boolean isGenerateSealedInterfaces() { public Map getCustomTypesMapping() { return config.getCustomTypesMapping(); } + + @Override + public Map getCustomTemplates() { + return config.getCustomTemplates(); + } @Override public Map> getCustomAnnotationsMapping() { diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenAnnotationsTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenAnnotationsTest.java index 9c1e23ae7..3180ebb4a 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenAnnotationsTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenAnnotationsTest.java @@ -1,5 +1,6 @@ package com.kobylynskyi.graphql.codegen; +import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType; import com.kobylynskyi.graphql.codegen.java.JavaGraphQLCodegen; import com.kobylynskyi.graphql.codegen.model.MappingConfig; import com.kobylynskyi.graphql.codegen.utils.Utils; @@ -327,4 +328,14 @@ private void generate(String path) throws IOException { TestUtils.getStaticGeneratedInfo(mappingConfig)).generate(); } + @Test + void generate_CustomTemplates_Type() throws Exception { + mappingConfig.putCustomTemplatesIfAbsent(FreeMarkerTemplateType.TYPE, "/template/record_type.ftl"); + + generate("src/test/resources/schemas/test.graphqls"); + + File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); + assertFileContainsElements(files, "Event.java", + "public record Event ("); + } } diff --git a/src/test/resources/template/record_type.ftl b/src/test/resources/template/record_type.ftl new file mode 100644 index 000000000..3ed480643 --- /dev/null +++ b/src/test/resources/template/record_type.ftl @@ -0,0 +1,19 @@ +<#assign MapperUtil=statics["com.kobylynskyi.graphql.codegen.java.JavaGraphQLTypeMapper"]> +<#if package?has_content> +package ${package}; + + +public record ${className} ( +<#if fields?has_content> + <#list fields as field> + ${field.type} ${field.name}<#if field.defaultValue?has_content> = ${field.defaultValue}<#if field?has_next>, + + +) +{ + + public ${className}() { + <#list fields as field><#if field.defaultValue?has_content> ${field.name} = ${field.defaultValue}; + } + +} From 04966b620e39fbbc331b7c4acf487273215f6109 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 20 Mar 2023 08:47:33 +1300 Subject: [PATCH 02/10] Update src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java Co-authored-by: Bogdan Kobylynskyi <92bogdan@gmail.com> --- .../com/kobylynskyi/graphql/codegen/model/MappingConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java index b102cac7f..56726b3d1 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java @@ -249,7 +249,7 @@ public void setCustomTypesMapping(Map customTypesMapping) { } /** - * Put custom template if absent. + * Provide a path to a custom template for the specific FreeMarker template type (if absent). * * @param from the from * @param to the to From 0de6ef6a13ca63f5b041335348f6ac7fb76bfe09 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 20 Mar 2023 08:53:49 +1300 Subject: [PATCH 03/10] Address PR comments --- .../graphql/codegen/GraphQLCodegenMojo.java | 5 +- .../FreeMarkerTemplateFilesCreator.java | 8 +-- .../graphql/codegen/model/MappingConfig.java | 3 +- .../GraphQLCodegenAnnotationsTest.java | 11 ---- .../GraphQLCodegenCustomTemplatesTest.java | 54 +++++++++++++++++++ 5 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenCustomTemplatesTest.java diff --git a/plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java b/plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java index 9c3ded048..d47f9dc9b 100644 --- a/plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java +++ b/plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java @@ -744,7 +744,10 @@ private static Map convertToMap(Properties properties) { @Override public Map getCustomTemplates() { - return customTemplates; + if (customTemplates == null) { + return new HashMap<>(); + } + return customTemplates; } } diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java b/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java index 69de8ee29..4e333c7c0 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java @@ -49,11 +49,11 @@ public static File create(MappingContext mappingContext, try (FileWriter fileWriter = new FileWriter(javaSourceFile)) { Template template; - if (mappingContext.getCustomTemplates().containsKey(templateType)) { - template = FreeMarkerTemplatesRegistry.getCustomTemplates(mappingContext.getCustomTemplates().get(templateType)); + String templatePath = mappingContext.getCustomTemplates().get(templateType); + if (templatePath != null) { + template = FreeMarkerTemplatesRegistry.getCustomTemplates(templatePath); } else { - template = - FreeMarkerTemplatesRegistry.getTemplateWithLang(language, templateType); + template = FreeMarkerTemplatesRegistry.getTemplateWithLang(language, templateType); } template.process(dataModel, fileWriter); } catch (Exception e) { diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java index 56726b3d1..925965999 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java @@ -1,7 +1,6 @@ package com.kobylynskyi.graphql.codegen.model; import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType; -import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -256,7 +255,7 @@ public void setCustomTypesMapping(Map customTypesMapping) { */ public void putCustomTemplatesIfAbsent(FreeMarkerTemplateType from, String to) { if (customTemplates == null) { - customTemplates = new HashMap<>(); + customTemplates = new HashMap<>(); } customTemplates.computeIfAbsent(from, k -> to); } diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenAnnotationsTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenAnnotationsTest.java index 3180ebb4a..9c1e23ae7 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenAnnotationsTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenAnnotationsTest.java @@ -1,6 +1,5 @@ package com.kobylynskyi.graphql.codegen; -import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType; import com.kobylynskyi.graphql.codegen.java.JavaGraphQLCodegen; import com.kobylynskyi.graphql.codegen.model.MappingConfig; import com.kobylynskyi.graphql.codegen.utils.Utils; @@ -328,14 +327,4 @@ private void generate(String path) throws IOException { TestUtils.getStaticGeneratedInfo(mappingConfig)).generate(); } - @Test - void generate_CustomTemplates_Type() throws Exception { - mappingConfig.putCustomTemplatesIfAbsent(FreeMarkerTemplateType.TYPE, "/template/record_type.ftl"); - - generate("src/test/resources/schemas/test.graphqls"); - - File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); - assertFileContainsElements(files, "Event.java", - "public record Event ("); - } } diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenCustomTemplatesTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenCustomTemplatesTest.java new file mode 100644 index 000000000..e965414fd --- /dev/null +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenCustomTemplatesTest.java @@ -0,0 +1,54 @@ +package com.kobylynskyi.graphql.codegen; + +import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType; +import com.kobylynskyi.graphql.codegen.java.JavaGraphQLCodegen; +import com.kobylynskyi.graphql.codegen.model.MappingConfig; +import com.kobylynskyi.graphql.codegen.utils.Utils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.util.Objects; + +import static com.kobylynskyi.graphql.codegen.TestUtils.assertFileContainsElements; +import static java.util.Collections.singletonList; + +class GraphQLCodegenCustomTemplatesTest { + + private final File outputBuildDir = new File("build/generated"); + private final File outputJavaClassesDir = new File("build/generated/com/kobylynskyi/graphql/test1"); + + private MappingConfig mappingConfig; + + @BeforeEach + void init() { + mappingConfig = new MappingConfig(); + mappingConfig.setPackageName("com.kobylynskyi.graphql.test1"); + mappingConfig.setGenerateClient(true); + } + + @AfterEach + void cleanup() { + Utils.deleteDir(outputBuildDir); + } + + @Test + void generate_CustomTemplates_Type() throws Exception { + mappingConfig.putCustomTemplatesIfAbsent(FreeMarkerTemplateType.TYPE, "/template/record_type.ftl"); + + generate("src/test/resources/schemas/test.graphqls"); + + File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); + assertFileContainsElements(files, "Event.java", + "public record Event ("); + } + + private void generate(String path) throws IOException { + new JavaGraphQLCodegen(singletonList(path), + outputBuildDir, mappingConfig, TestUtils.getStaticGeneratedInfo(mappingConfig)) + .generate(); + } + +} From 2068170ca2822f2f966222c5fabffdc481ab9e13 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 20 Mar 2023 09:09:30 +1300 Subject: [PATCH 04/10] Add customTemplates configuration to sbt and gradle --- docs/codegen-options.md | 1 + .../gradle/GraphQLCodegenGradleTask.java | 17 +++++++++++++++-- .../graphql/codegen/GraphQLCodegenKeys.scala | 3 +++ .../graphql/codegen/GraphQLCodegenPlugin.scala | 2 ++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/codegen-options.md b/docs/codegen-options.md index 0ea1dbe10..1d09e3df3 100644 --- a/docs/codegen-options.md +++ b/docs/codegen-options.md @@ -31,6 +31,7 @@ | `typeResolverPrefix` | String | Empty | Sets the prefix for GraphQL type resolver classes. | | `typeResolverSuffix` | String | `Resolver` | Sets the suffix for GraphQL type resolver classes. | | `customTypesMapping` | Map(String,String) | Empty | *See [CustomTypesMapping](#option-customtypesmapping)* | +| `customTemplates` | Map(FreeMarkerTemplateType,String) | Empty | Use to supply custom template for code generation | | `customAnnotationsMapping` | Map(String,String[]) | Empty | *See [CustomAnnotationsMapping](#option-customannotationsmapping)* | | `directiveAnnotationsMapping` | Map(String,String[]) | Empty | *See [DirectiveAnnotationsMapping](#option-directiveannotationsmapping)* | | `fieldsWithResolvers` | Set(String) | Empty | Fields that require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. E.g.: `Person`, `Person.friends`, `@customResolver`. | diff --git a/plugins/gradle/graphql-java-codegen-gradle-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/gradle/GraphQLCodegenGradleTask.java b/plugins/gradle/graphql-java-codegen-gradle-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/gradle/GraphQLCodegenGradleTask.java index 1dbff1ca6..244454bfc 100644 --- a/plugins/gradle/graphql-java-codegen-gradle-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/gradle/GraphQLCodegenGradleTask.java +++ b/plugins/gradle/graphql-java-codegen-gradle-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/gradle/GraphQLCodegenGradleTask.java @@ -1,6 +1,7 @@ package io.github.kobylynskyi.graphql.codegen.gradle; import com.kobylynskyi.graphql.codegen.GraphQLCodegen; +import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType; import com.kobylynskyi.graphql.codegen.java.JavaGraphQLCodegen; import com.kobylynskyi.graphql.codegen.kotlin.KotlinGraphQLCodegen; import com.kobylynskyi.graphql.codegen.model.ApiInterfaceStrategy; @@ -54,6 +55,7 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode private Map customTypesMapping = new HashMap<>(); private Map> customAnnotationsMapping = new HashMap<>(); + private Map customTemplates = new HashMap<>(); private Map> directiveAnnotationsMapping = new HashMap<>(); private String packageName; private String apiPackageName; @@ -133,8 +135,8 @@ public void generate() throws Exception { mappingConfig.setPackageName(packageName); mappingConfig.setCustomTypesMapping( customTypesMapping != null ? customTypesMapping : new HashMap<>()); - mappingConfig.setCustomAnnotationsMapping( - customAnnotationsMapping != null ? customAnnotationsMapping : new HashMap<>()); + mappingConfig.setCustomTemplates( + customTemplates != null ? customTemplates : new HashMap<>()); mappingConfig.setDirectiveAnnotationsMapping( directiveAnnotationsMapping != null ? directiveAnnotationsMapping : new HashMap<>()); mappingConfig.setApiNameSuffix(apiNameSuffix); @@ -333,6 +335,17 @@ public void setCustomTypesMapping(Map customTypesMapping) { this.customTypesMapping = customTypesMapping; } + @Input + @Optional + @Override + public Map getCustomTemplates() { + return customTemplates; + } + + public void setCustomTemplates(Map customTemplates) { + this.customTemplates = customTemplates; + } + @Input @Optional @Override diff --git a/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenKeys.scala b/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenKeys.scala index 3c63e379c..acc45095b 100644 --- a/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenKeys.scala +++ b/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenKeys.scala @@ -3,6 +3,7 @@ package io.github.dreamylost.graphql.codegen import java.util import com.kobylynskyi.graphql.codegen.model._ +import com.kobylynskyi.graphql.codegen.generators._ import sbt._ /** @author @@ -43,6 +44,8 @@ trait GraphQLCodegenKeys { val customAnnotationsMapping = settingKey[util.Map[String, util.List[String]]]("customAnnotationsMapping") + val customTemplates = settingKey[util.Map[FreeMarkerTemplateType, String]]("customTemplates") + val generateEqualsAndHashCode = settingKey[Boolean]("Specifies whether generated model classes should have equals and hashCode methods defined.") diff --git a/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenPlugin.scala b/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenPlugin.scala index 0fe649e68..702b5565a 100644 --- a/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenPlugin.scala +++ b/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenPlugin.scala @@ -67,6 +67,7 @@ class GraphQLCodegenPlugin(configuration: Configuration, private[codegen] val co generateJacksonTypeIdResolver := MappingConfigConstants.DEFAULT_GENERATE_JACKSON_TYPE_ID_RESOLVER, customTypesMapping := new JHashMap[String, String](), // TODO use scala Map, convert to java Map customAnnotationsMapping := new JHashMap[String, JList[String]](), + customTemplates := new JHashMap[FreeMarkerTemplateType, String](), directiveAnnotationsMapping := new JHashMap[String, JList[String]](), javaxValidationApiVersion := None, graphqlJavaCodegenVersion := None, @@ -149,6 +150,7 @@ class GraphQLCodegenPlugin(configuration: Configuration, private[codegen] val co mappingConfig.setTypeResolverPrefix((GraphQLCodegenConfig / typeResolverPrefix).value.orNull) mappingConfig.setModelValidationAnnotation((GraphQLCodegenConfig / modelValidationAnnotation).value) mappingConfig.setCustomAnnotationsMapping((GraphQLCodegenConfig / customAnnotationsMapping).value) + mappingConfig.setCustomTemplates((GraphQLCodegenConfig / customTemplates).value) mappingConfig.setGenerateEqualsAndHashCode((GraphQLCodegenConfig / generateEqualsAndHashCode).value) mappingConfig.setGenerateImmutableModels((GraphQLCodegenConfig / generateImmutableModels).value) mappingConfig.setGenerateToString((GraphQLCodegenConfig / generateToString).value) From 85f7ad07c1b3691d6dd24a8414770077d0a41a07 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 20 Mar 2023 09:22:16 +1300 Subject: [PATCH 05/10] Change instructions on how to test maven plugin from top level project --- CONTRIBUTING.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 57e627d2a..929f2c3e8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,8 +36,7 @@ Please follow the steps below in order to make the changes: ./gradlew -p plugins/gradle/graphql-java-codegen-gradle-plugin clean build # Build Maven plugin - cd plugins/maven/graphql-java-codegen-maven-plugin - mvn clean verify + mvn clean verify -f plugins/maven/graphql-java-codegen-maven-plugin/pom.xml ``` 9. Make changes to the plugin code @@ -48,8 +47,7 @@ Please follow the steps below in order to make the changes: ./gradlew -p plugins/gradle/graphql-java-codegen-gradle-plugin clean build publishToMavenLocal # Install Maven plugin - cd plugins/maven/graphql-java-codegen-maven-plugin - mvn clean install + mvn clean install -f plugins/maven/graphql-java-codegen-maven-plugin/pom.xml ``` 11. Make sure that `example` projects are compiling and running. From e1864bad245ea2da3b423e52702adc749d8ceb38 Mon Sep 17 00:00:00 2001 From: Bogdan Kobylynskyi <92bogdan@gmail.com> Date: Sun, 19 Mar 2023 17:14:41 -0400 Subject: [PATCH 06/10] Cosmetic formatting changes --- docs/codegen-options.md | 132 +++++++++--------- .../FreeMarkerTemplateFilesCreator.java | 2 +- .../model/GraphQLCodegenConfiguration.java | 4 +- .../graphql/codegen/model/MappingConfig.java | 4 +- 4 files changed, 71 insertions(+), 71 deletions(-) diff --git a/docs/codegen-options.md b/docs/codegen-options.md index 1d09e3df3..6801803a8 100644 --- a/docs/codegen-options.md +++ b/docs/codegen-options.md @@ -1,71 +1,71 @@ # Codegen Options -| Option | Data Type | Default value | Description | -|:-----------------------------------------------------:|:---------------------------------------------------------------------:|:--------------------------------------------------------------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `graphqlSchemaPaths` | List(String) | (falls back to `graphqlSchemas`) | GraphQL schema locations. You can supply multiple paths to GraphQL schemas. To include many schemas from a folder hierarchy, use the `graphqlSchemas` block instead. | -| `graphqlSchemas` | *See
[graphqlSchemas](#option-graphqlschemas)* | All
`.graphqls`/`.graphql`
files in
resources | Block to define the input GraphQL schemas, when exact paths are too cumbersome. See table below for a list of options. *See [graphqlSchemas](#option-graphqlschemas)* | -| `graphqlQueryIntrospectionResu`
`ltPath` | String | None | Path to GraphQL Introspection Query result in json format (with root object `__schema` or `data.__schema`). Sample: [sample-introspection-query-result.json](../src/test/resources/introspection-result/sample-introspection-query-result.json) | -| `outputDir` | String | None | The output target directory into which code will be generated. | -| `configurationFiles` | List(String) | Empty | Paths to the files with mapping configurations. Supported formats. JSON, HOCON. Order of specified configuration files matters, so the default configuration should be placed at the end. | -| `packageName` | String | Empty | Java package for generated classes. | -| `apiPackageName` | String | Empty | Java package for generated api classes (Query, Mutation, Subscription). | -| `modelPackageName` | String | Empty | Java package for generated model classes (type, input, interface, enum, union). | -| `generateBuilder` | Boolean | True | Specifies whether generated model classes should have builder. | -| `generateApis` | Boolean | True | Specifies whether api classes should be generated as well as model classes. | -| `generateDataFetchingEnvironme`
`ntArgumentInApis` | Boolean | False | If true, then `graphql.schema.DataFetchingEnvironment env` will be added as a last argument to all methods of root type resolvers and field resolvers. | -| `generateEqualsAndHashCode` | Boolean | False | Specifies whether generated model classes should have equals and hashCode methods defined. | -| `generateParameterizedFieldsResolvers` | Boolean | True | Specifies whether separate `Resolver` interface for parametrized fields should be generated. If `false`, then add parametrized field to the type definition and ignore field parameters. If `true` then separate `Resolver` interface for parametrized fields will be generated. | -| `generateImmutableModels` | Boolean | False | Specifies whether generated model classes should be immutable. | -| `generateToString` | Boolean | False | Specifies whether generated model classes should have toString method defined. | -| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. | -| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. | -| `generatedAnnotation` | String | `jakarta.annotation.Generated`
`javax.annotation.Generated` | Qualified class name (with package) of the `@Generated` annotation that will be added on top of every generated class (if `addGeneratedAnnotation` is **true**) | -| `apiNamePrefix` | String | Empty | Sets the prefix for GraphQL api classes (query, mutation, subscription). | -| `apiNameSuffix` | String | `Resolver` | Sets the suffix for GraphQL api classes (query, mutation, subscription). | -| `apiInterfaceStrategy` | *See
[ApiInterfaceStrategy](#option-apiinterfacestrategy)* | `INTERFACE_PER_OPERATION` | *See [ApiInterfaceStrategy](#option-apiinterfacestrategy)* | -| `apiRootInterfaceStrategy` | *See
[ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | `SINGLE_INTERFACE` | *See [ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | -| `apiNamePrefixStrategy` | *See
[ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | `CONSTANT` | *See [ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | -| `modelNamePrefix` | String | Empty | Sets the prefix for GraphQL model classes (type, input, interface, enum, union). | -| `modelNameSuffix` | String | Empty | Sets the suffix for GraphQL model classes (type, input, interface, enum, union). | -| `modelValidationAnnotation` | String | `@javax.validation.`
`constraints.NotNull` | Annotation for mandatory (NonNull) fields. Can be null/empty. | -| `typeResolverPrefix` | String | Empty | Sets the prefix for GraphQL type resolver classes. | -| `typeResolverSuffix` | String | `Resolver` | Sets the suffix for GraphQL type resolver classes. | -| `customTypesMapping` | Map(String,String) | Empty | *See [CustomTypesMapping](#option-customtypesmapping)* | -| `customTemplates` | Map(FreeMarkerTemplateType,String) | Empty | Use to supply custom template for code generation | -| `customAnnotationsMapping` | Map(String,String[]) | Empty | *See [CustomAnnotationsMapping](#option-customannotationsmapping)* | -| `directiveAnnotationsMapping` | Map(String,String[]) | Empty | *See [DirectiveAnnotationsMapping](#option-directiveannotationsmapping)* | -| `fieldsWithResolvers` | Set(String) | Empty | Fields that require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. E.g.: `Person`, `Person.friends`, `@customResolver`. | -| `fieldsWithoutResolvers` | Set(String) | Empty | Fields that DO NOT require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. Can be used in conjunction with `generateExtensionFieldsResolvers` option. E.g.: `Person`, `Person.friends`, `@noResolver`. | -| `resolverArgumentAnnotations` | Set(String) | Empty | Annotations that will be added to all resolver arguments. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.Argument` | -| `parametrizedResolverAnnotations` | Set(String) | Empty | Annotations that will be added to all parametrized resolver methods. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="{{TYPE_NAME}}")` | -| `generateParameterizedFieldsResolvers` | Boolean | True | If true, then generate separate `Resolver` interface for parametrized fields. If false, then add field to the type definition and ignore field parameters. | -| `generateExtensionFieldsResolvers` | Boolean | False | Specifies whether all fields in extensions (`extend type` and `extend interface`) should be present in Resolver interface instead of the type class itself. | -| `generateModelsForRootTypes` | Boolean | False | Specifies whether model classes should be generated for `type Query`, `type Subscription`, `type Mutation`. | -| `useOptionalForNullableReturnTypes` | Boolean | False | Specifies whether nullable return types of api methods should be wrapped into [`java.util.Optional<>`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Optional.html). Lists will not be wrapped. | -| `generateApisWithThrowsException` | Boolean | True | Specifies whether api interface methods should have `throws Exception` in signature. | -| `generateNoArgsConstructorOnly` | Boolean | False | Specifies whether model classes should only have a no-args constructor. All-args constructor will not be generated in case value is true | -| `generateModelsWithPublicFields` | Boolean | False | Specifies whether model classes should have public fields and NO getters/setters. By default, fields are private and there are getters/setters for each field. | -| `apiReturnType` | String | Empty | Return type for api methods (query/mutation). For example: `reactor.core.publisher.Mono`, etc. | -| `apiReturnListType` | String | Empty | Return type for api methods (query/mutation) having list type. For example: `reactor.core.publisher.Flux`, etc. By default is empty, so `apiReturnType` will be used. | -| `subscriptionReturnType` | String | Empty | Return type for subscription methods. For example: `org.reactivestreams.Publisher`, `io.reactivex.Observable`, etc. | -| `relayConfig` | *See
[RelayConfig](#option-relayconfig)* | `@connection(for: ...)` | *See [RelayConfig](#option-relayconfig)* | -| `generateClient` | Boolean | False | Specifies whether client-side classes should be generated for each query, mutation and subscription. This includes: `Request` classes (contain input data), `ResponseProjection` classes for each type (contain response fields) and `Response` classes (contain response data). | -| `requestSuffix` | String | Request | Sets the suffix for `Request` classes. | -| `responseSuffix` | String | Response | Sets the suffix for `Response` classes. | -| `responseProjectionSuffix` | String | ResponseProjection | Sets the suffix for `ResponseProjection` classes. | -| `parametrizedInputSuffix` | String | ParametrizedInput | Sets the suffix for `ParametrizedInput` classes. | -| `parentInterfaces` | *See
[parentInterfaces](#option-parentinterfaces)* | Empty | Block to define parent interfaces for generated interfaces (query / mutation / subscription / type resolver). *See [parentInterfaces](#option-parentinterfaces)* | -| `generateAllMethodInProjection` | Boolean | True | Enables whether the `all$()` method should be generated in the projection classes. Disabling enforces the client to select the fields manually. | -| `responseProjectionMaxDepth` | Integer | 3 | Sets max depth when use `all$()` which for facilitating the construction of projection automatically, the fields on all projections are provided when it be invoked. This is a global configuration, of course, you can use `all$(max)` to set for each method. For self recursive types, too big depth may result in a large number of returned data! | -| `generatedLanguage` | Enum | GeneratedLanguage.JAVA | Choose which language you want to generate, Java,Scala,Kotlin were supported. Note that due to language features, there are slight differences in default values between languages. | -| `generateModelOpenClasses` | Boolean | False | The class type of the generated model. If true, generate normal classes, else generate data classes. It only support in kotlin(```data class```) and scala(```case class```). Maybe we will consider to support Java ```record``` in the future. | -| `initializeNullableTypes` | Boolean | False | Adds a default null value to nullable arguments. Only supported in Kotlin. | -| `generateSealedInterfaces` | Boolean | False | This applies to generated interfaces on unions and interfaces. If true, generate sealed interfaces, else generate normal ones. It is only supported in Kotlin and Scala. | -| `typesAsInterfaces` | Set(String) | Empty | Types that must generated as interfaces should be defined here in format: `TypeName` or `@directive`. E.g.: `User`, `@asInterface`. | -| `useObjectMapperForRequestSerialization` | Set(String) | Empty | Fields that require serialization using `com.fasterxml.jackson.databind.ObjectMapper#writeValueAsString(Object)`. Values should be defined here in the following format: `GraphqlObjectName.fieldName` or `GraphqlTypeName`. If just type is specified, then all fields of this type will be serialized using ObjectMapper. E.g.: `["Person.createdDateTime", ZonedDateTime"]` | -| `supportUnknownFields` | Boolean | False | Specifies whether api classes should support unknown fields during serialization or deserialization. If `true`, classes will include a property of type [`java.util.Map`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) that will store unknown fields. | -| `unknownFieldsPropertyName` | String | userDefinedFields | Specifies the name of the property to be included in api classes to support unknown fields during serialization or deserialization | -| `skip` | Boolean | False | If true, then code generation will not happen | +| Option | Data Type | Default value | Description | +|:-----------------------------------------------------:|:----------------------------------------------------------------------:|:--------------------------------------------------------------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `graphqlSchemaPaths` | List(String) | (falls back to `graphqlSchemas`) | GraphQL schema locations. You can supply multiple paths to GraphQL schemas. To include many schemas from a folder hierarchy, use the `graphqlSchemas` block instead. | +| `graphqlSchemas` | *See
[graphqlSchemas](#option-graphqlschemas)* | All
`.graphqls`/`.graphql`
files in
resources | Block to define the input GraphQL schemas, when exact paths are too cumbersome. See table below for a list of options. *See [graphqlSchemas](#option-graphqlschemas)* | +| `graphqlQueryIntrospectionResu`
`ltPath` | String | None | Path to GraphQL Introspection Query result in json format (with root object `__schema` or `data.__schema`). Sample: [sample-introspection-query-result.json](../src/test/resources/introspection-result/sample-introspection-query-result.json) | +| `outputDir` | String | None | The output target directory into which code will be generated. | +| `configurationFiles` | List(String) | Empty | Paths to the files with mapping configurations. Supported formats. JSON, HOCON. Order of specified configuration files matters, so the default configuration should be placed at the end. | +| `packageName` | String | Empty | Java package for generated classes. | +| `apiPackageName` | String | Empty | Java package for generated api classes (Query, Mutation, Subscription). | +| `modelPackageName` | String | Empty | Java package for generated model classes (type, input, interface, enum, union). | +| `generateBuilder` | Boolean | True | Specifies whether generated model classes should have builder. | +| `generateApis` | Boolean | True | Specifies whether api classes should be generated as well as model classes. | +| `generateDataFetchingEnvironme`
`ntArgumentInApis` | Boolean | False | If true, then `graphql.schema.DataFetchingEnvironment env` will be added as a last argument to all methods of root type resolvers and field resolvers. | +| `generateEqualsAndHashCode` | Boolean | False | Specifies whether generated model classes should have equals and hashCode methods defined. | +| `generateParameterizedFieldsResolvers` | Boolean | True | Specifies whether separate `Resolver` interface for parametrized fields should be generated. If `false`, then add parametrized field to the type definition and ignore field parameters. If `true` then separate `Resolver` interface for parametrized fields will be generated. | +| `generateImmutableModels` | Boolean | False | Specifies whether generated model classes should be immutable. | +| `generateToString` | Boolean | False | Specifies whether generated model classes should have toString method defined. | +| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. | +| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. | +| `generatedAnnotation` | String | `jakarta.annotation.Generated`
`javax.annotation.Generated` | Qualified class name (with package) of the `@Generated` annotation that will be added on top of every generated class (if `addGeneratedAnnotation` is **true**) | +| `apiNamePrefix` | String | Empty | Sets the prefix for GraphQL api classes (query, mutation, subscription). | +| `apiNameSuffix` | String | `Resolver` | Sets the suffix for GraphQL api classes (query, mutation, subscription). | +| `apiInterfaceStrategy` | *See
[ApiInterfaceStrategy](#option-apiinterfacestrategy)* | `INTERFACE_PER_OPERATION` | *See [ApiInterfaceStrategy](#option-apiinterfacestrategy)* | +| `apiRootInterfaceStrategy` | *See
[ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | `SINGLE_INTERFACE` | *See [ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | +| `apiNamePrefixStrategy` | *See
[ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | `CONSTANT` | *See [ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | +| `modelNamePrefix` | String | Empty | Sets the prefix for GraphQL model classes (type, input, interface, enum, union). | +| `modelNameSuffix` | String | Empty | Sets the suffix for GraphQL model classes (type, input, interface, enum, union). | +| `modelValidationAnnotation` | String | `@javax.validation.`
`constraints.NotNull` | Annotation for mandatory (NonNull) fields. Can be null/empty. | +| `typeResolverPrefix` | String | Empty | Sets the prefix for GraphQL type resolver classes. | +| `typeResolverSuffix` | String | `Resolver` | Sets the suffix for GraphQL type resolver classes. | +| `customTypesMapping` | Map(String,String) | Empty | *See [CustomTypesMapping](#option-customtypesmapping)* | +| `customTemplates` | Map(FreeMarkerTemplateType,String) | Empty | Use to supply paths to custom FreeMarker templates for code generation. | +| `customAnnotationsMapping` | Map(String,String[]) | Empty | *See [CustomAnnotationsMapping](#option-customannotationsmapping)* | +| `directiveAnnotationsMapping` | Map(String,String[]) | Empty | *See [DirectiveAnnotationsMapping](#option-directiveannotationsmapping)* | +| `fieldsWithResolvers` | Set(String) | Empty | Fields that require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. E.g.: `Person`, `Person.friends`, `@customResolver`. | +| `fieldsWithoutResolvers` | Set(String) | Empty | Fields that DO NOT require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. Can be used in conjunction with `generateExtensionFieldsResolvers` option. E.g.: `Person`, `Person.friends`, `@noResolver`. | +| `resolverArgumentAnnotations` | Set(String) | Empty | Annotations that will be added to all resolver arguments. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.Argument` | +| `parametrizedResolverAnnotations` | Set(String) | Empty | Annotations that will be added to all parametrized resolver methods. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="{{TYPE_NAME}}")` | +| `generateParameterizedFieldsResolvers` | Boolean | True | If true, then generate separate `Resolver` interface for parametrized fields. If false, then add field to the type definition and ignore field parameters. | +| `generateExtensionFieldsResolvers` | Boolean | False | Specifies whether all fields in extensions (`extend type` and `extend interface`) should be present in Resolver interface instead of the type class itself. | +| `generateModelsForRootTypes` | Boolean | False | Specifies whether model classes should be generated for `type Query`, `type Subscription`, `type Mutation`. | +| `useOptionalForNullableReturnTypes` | Boolean | False | Specifies whether nullable return types of api methods should be wrapped into [`java.util.Optional<>`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Optional.html). Lists will not be wrapped. | +| `generateApisWithThrowsException` | Boolean | True | Specifies whether api interface methods should have `throws Exception` in signature. | +| `generateNoArgsConstructorOnly` | Boolean | False | Specifies whether model classes should only have a no-args constructor. All-args constructor will not be generated in case value is true | +| `generateModelsWithPublicFields` | Boolean | False | Specifies whether model classes should have public fields and NO getters/setters. By default, fields are private and there are getters/setters for each field. | +| `apiReturnType` | String | Empty | Return type for api methods (query/mutation). For example: `reactor.core.publisher.Mono`, etc. | +| `apiReturnListType` | String | Empty | Return type for api methods (query/mutation) having list type. For example: `reactor.core.publisher.Flux`, etc. By default is empty, so `apiReturnType` will be used. | +| `subscriptionReturnType` | String | Empty | Return type for subscription methods. For example: `org.reactivestreams.Publisher`, `io.reactivex.Observable`, etc. | +| `relayConfig` | *See
[RelayConfig](#option-relayconfig)* | `@connection(for: ...)` | *See [RelayConfig](#option-relayconfig)* | +| `generateClient` | Boolean | False | Specifies whether client-side classes should be generated for each query, mutation and subscription. This includes: `Request` classes (contain input data), `ResponseProjection` classes for each type (contain response fields) and `Response` classes (contain response data). | +| `requestSuffix` | String | Request | Sets the suffix for `Request` classes. | +| `responseSuffix` | String | Response | Sets the suffix for `Response` classes. | +| `responseProjectionSuffix` | String | ResponseProjection | Sets the suffix for `ResponseProjection` classes. | +| `parametrizedInputSuffix` | String | ParametrizedInput | Sets the suffix for `ParametrizedInput` classes. | +| `parentInterfaces` | *See
[parentInterfaces](#option-parentinterfaces)* | Empty | Block to define parent interfaces for generated interfaces (query / mutation / subscription / type resolver). *See [parentInterfaces](#option-parentinterfaces)* | +| `generateAllMethodInProjection` | Boolean | True | Enables whether the `all$()` method should be generated in the projection classes. Disabling enforces the client to select the fields manually. | +| `responseProjectionMaxDepth` | Integer | 3 | Sets max depth when use `all$()` which for facilitating the construction of projection automatically, the fields on all projections are provided when it be invoked. This is a global configuration, of course, you can use `all$(max)` to set for each method. For self recursive types, too big depth may result in a large number of returned data! | +| `generatedLanguage` | Enum | GeneratedLanguage.JAVA | Choose which language you want to generate, Java,Scala,Kotlin were supported. Note that due to language features, there are slight differences in default values between languages. | +| `generateModelOpenClasses` | Boolean | False | The class type of the generated model. If true, generate normal classes, else generate data classes. It only support in kotlin(```data class```) and scala(```case class```). Maybe we will consider to support Java ```record``` in the future. | +| `initializeNullableTypes` | Boolean | False | Adds a default null value to nullable arguments. Only supported in Kotlin. | +| `generateSealedInterfaces` | Boolean | False | This applies to generated interfaces on unions and interfaces. If true, generate sealed interfaces, else generate normal ones. It is only supported in Kotlin and Scala. | +| `typesAsInterfaces` | Set(String) | Empty | Types that must generated as interfaces should be defined here in format: `TypeName` or `@directive`. E.g.: `User`, `@asInterface`. | +| `useObjectMapperForRequestSerialization` | Set(String) | Empty | Fields that require serialization using `com.fasterxml.jackson.databind.ObjectMapper#writeValueAsString(Object)`. Values should be defined here in the following format: `GraphqlObjectName.fieldName` or `GraphqlTypeName`. If just type is specified, then all fields of this type will be serialized using ObjectMapper. E.g.: `["Person.createdDateTime", ZonedDateTime"]` | +| `supportUnknownFields` | Boolean | False | Specifies whether api classes should support unknown fields during serialization or deserialization. If `true`, classes will include a property of type [`java.util.Map`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) that will store unknown fields. | +| `unknownFieldsPropertyName` | String | userDefinedFields | Specifies the name of the property to be included in api classes to support unknown fields during serialization or deserialization | +| `skip` | Boolean | False | If true, then code generation will not happen | ### Option `graphqlSchemas` diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java b/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java index 4e333c7c0..9dd5273d8 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java @@ -51,7 +51,7 @@ public static File create(MappingContext mappingContext, Template template; String templatePath = mappingContext.getCustomTemplates().get(templateType); if (templatePath != null) { - template = FreeMarkerTemplatesRegistry.getCustomTemplates(templatePath); + template = FreeMarkerTemplatesRegistry.getCustomTemplates(templatePath); } else { template = FreeMarkerTemplatesRegistry.getTemplateWithLang(language, templateType); } diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java index 6a9894c57..c6755b953 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java @@ -30,9 +30,9 @@ public interface GraphQLCodegenConfiguration { Map getCustomTypesMapping(); /** - * Can be used to supply custom template for code generation + * Can be used to supply paths to custom FreeMarker templates for code generation. * - * @return template to generate sources from + * @return a map, where key is a tempalte type and a value is path to a FreeMarker template */ Map getCustomTemplates(); diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java index 925965999..d50980fca 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java @@ -262,11 +262,11 @@ public void putCustomTemplatesIfAbsent(FreeMarkerTemplateType from, String to) { @Override public Map getCustomTemplates() { - return customTemplates; + return customTemplates; } public void setCustomTemplates(Map customTemplates) { - this.customTemplates = customTemplates; + this.customTemplates = customTemplates; } @Override From 4f927e5c5ee2f69b5638908bfc5692480facb48b Mon Sep 17 00:00:00 2001 From: Bogdan Kobylynskyi <92bogdan@gmail.com> Date: Sun, 19 Mar 2023 17:19:27 -0400 Subject: [PATCH 07/10] Null-check for customTemplates map --- .../FreeMarkerTemplateFilesCreator.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java b/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java index 9dd5273d8..837295e0a 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java @@ -48,13 +48,7 @@ public static File create(MappingContext mappingContext, } try (FileWriter fileWriter = new FileWriter(javaSourceFile)) { - Template template; - String templatePath = mappingContext.getCustomTemplates().get(templateType); - if (templatePath != null) { - template = FreeMarkerTemplatesRegistry.getCustomTemplates(templatePath); - } else { - template = FreeMarkerTemplatesRegistry.getTemplateWithLang(language, templateType); - } + Template template = getTemplateForTypeAndLanguage(mappingContext, templateType, language); template.process(dataModel, fileWriter); } catch (Exception e) { throw new UnableToCreateFileException(e); @@ -62,6 +56,20 @@ public static File create(MappingContext mappingContext, return javaSourceFile; } + private static Template getTemplateForTypeAndLanguage(MappingContext mappingContext, + FreeMarkerTemplateType templateType, + GeneratedLanguage language) { + String templatePath = null; + if (mappingContext.getCustomTemplates() != null) { + templatePath = mappingContext.getCustomTemplates().get(templateType); + } + if (templatePath != null) { + return FreeMarkerTemplatesRegistry.getCustomTemplates(templatePath); + } else { + return FreeMarkerTemplatesRegistry.getTemplateWithLang(language, templateType); + } + } + private static File getFileTargetDirectory(Map dataModel, File outputDir) { File targetDir; Object packageName = dataModel.get(DataModelFields.PACKAGE); From 8ee4fa03a0472e6461dacf841bcdf393e3de7b71 Mon Sep 17 00:00:00 2001 From: Bogdan Kobylynskyi <92bogdan@gmail.com> Date: Sun, 19 Mar 2023 17:27:51 -0400 Subject: [PATCH 08/10] Add import to GraphQLCodegenPlugin.scala --- .../github/dreamylost/graphql/codegen/GraphQLCodegenPlugin.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenPlugin.scala b/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenPlugin.scala index 702b5565a..5551ee704 100644 --- a/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenPlugin.scala +++ b/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenPlugin.scala @@ -7,6 +7,7 @@ import com.kobylynskyi.graphql.codegen.model.exception.LanguageNotSupportedExcep import com.kobylynskyi.graphql.codegen.model.GeneratedLanguage._ import com.kobylynskyi.graphql.codegen.scala.ScalaGraphQLCodegen import com.kobylynskyi.graphql.codegen.supplier._ +import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType import sbt.{ AutoPlugin, PluginTrigger, _ } import sbt.Keys.{ sLog, sourceManaged, _ } import sbt.internal.util.complete.DefaultParsers.spaceDelimited From fa5dec6883dce5cfee8422f347e9dc4cec999a39 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 20 Mar 2023 10:30:40 +1300 Subject: [PATCH 09/10] Apply scalafmt --- .../codegen/GraphQLCodegenPlugin.scala | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenPlugin.scala b/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenPlugin.scala index 5551ee704..72a0c0474 100644 --- a/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenPlugin.scala +++ b/plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenPlugin.scala @@ -120,17 +120,17 @@ class GraphQLCodegenPlugin(configuration: Configuration, private[codegen] val co generateBuilder := MappingConfigConstants.DEFAULT_BUILDER, generateApis := MappingConfigConstants.DEFAULT_GENERATE_APIS, generateEqualsAndHashCode := MappingConfigConstants.DEFAULT_EQUALS_AND_HASHCODE, - generateImmutableModels := MappingConfigConstants.DEFAULT_GENERATE_IMMUTABLE_MODELS, // TODO change default value - generateToString := MappingConfigConstants.DEFAULT_TO_STRING, + generateImmutableModels := MappingConfigConstants.DEFAULT_GENERATE_IMMUTABLE_MODELS, // TODO change default value + generateToString := MappingConfigConstants.DEFAULT_TO_STRING, // parent interfaces configs: - parentInterfaces := parentInterfacesConfig, - generateAllMethodInProjection := MappingConfigConstants.DEFAULT_GENERATE_ALL_METHOD, - responseProjectionMaxDepth := MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_MAX_DEPTH, - supportUnknownFields := MappingConfigConstants.DEFAULT_SUPPORT_UNKNOWN_FIELDS, - unknownFieldsPropertyName := MappingConfigConstants.DEFAULT_UNKNOWN_FIELDS_PROPERTY_NAME, - generateNoArgsConstructorOnly := MappingConfigConstants.DEFAULT_GENERATE_NOARGS_CONSTRUCTOR_ONLY, - generateModelsWithPublicFields := MappingConfigConstants.DEFAULT_GENERATE_MODELS_WITH_PUBLIC_FIELDS, - skip := false + parentInterfaces := parentInterfacesConfig, + generateAllMethodInProjection := MappingConfigConstants.DEFAULT_GENERATE_ALL_METHOD, + responseProjectionMaxDepth := MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_MAX_DEPTH, + supportUnknownFields := MappingConfigConstants.DEFAULT_SUPPORT_UNKNOWN_FIELDS, + unknownFieldsPropertyName := MappingConfigConstants.DEFAULT_UNKNOWN_FIELDS_PROPERTY_NAME, + generateNoArgsConstructorOnly := MappingConfigConstants.DEFAULT_GENERATE_NOARGS_CONSTRUCTOR_ONLY, + generateModelsWithPublicFields := MappingConfigConstants.DEFAULT_GENERATE_MODELS_WITH_PUBLIC_FIELDS, + skip := false ) private def getMappingConfig(): Def.Initialize[MappingConfig] = Def.setting { From 30f875b823104502b0eba4203622bcca2d98f2a6 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 20 Mar 2023 10:38:36 +1300 Subject: [PATCH 10/10] Fix reviewdog violations --- .../kobylynskyi/graphql/codegen/model/MappingConfig.java | 8 ++++---- .../kobylynskyi/graphql/codegen/model/MappingContext.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java index d50980fca..46cc31f85 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java @@ -254,10 +254,10 @@ public void setCustomTypesMapping(Map customTypesMapping) { * @param to the to */ public void putCustomTemplatesIfAbsent(FreeMarkerTemplateType from, String to) { - if (customTemplates == null) { - customTemplates = new HashMap<>(); - } - customTemplates.computeIfAbsent(from, k -> to); + if (customTemplates == null) { + customTemplates = new HashMap<>(); + } + customTemplates.computeIfAbsent(from, k -> to); } @Override diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java index d929cc317..503f7d961 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java @@ -87,7 +87,7 @@ public Map getCustomTypesMapping() { @Override public Map getCustomTemplates() { - return config.getCustomTemplates(); + return config.getCustomTemplates(); } @Override