From d3eb4c931e1000981293baee3a8ea616077c6d9a Mon Sep 17 00:00:00 2001 From: Isaac Mercieca Date: Tue, 2 May 2023 21:20:06 +0200 Subject: [PATCH] Ability to supply a root directory with custom templates: "customTemplatesRoot" #1158 (#1198) * added support for specifying the template source for custom templates * formatted test sources * resolved issues with sbt plugin * formatted source class according to checkstyle rules * updated scala plugin to resolve to the working directory --------- Co-authored-by: Isaac Mercieca --- docs/codegen-options.md | 3 +- .../gradle/GraphQLCodegenGradleTask.java | 17 ++++++++++ .../graphql/codegen/GraphQLCodegenMojo.java | 9 ++++++ .../graphql/codegen/GraphQLCodegenKeys.scala | 2 ++ .../codegen/GraphQLCodegenPlugin.scala | 2 ++ .../FreeMarkerTemplateFilesCreator.java | 3 +- .../FreeMarkerTemplatesRegistry.java | 27 ++++++++++------ .../model/GraphQLCodegenConfiguration.java | 11 ++++++- .../graphql/codegen/model/MappingConfig.java | 31 +++++++++++++------ .../graphql/codegen/model/MappingContext.java | 7 ++++- .../GraphQLCodegenCustomTemplatesTest.java | 5 ++- 11 files changed, 94 insertions(+), 23 deletions(-) diff --git a/docs/codegen-options.md b/docs/codegen-options.md index 0580d1fa..a8b86b76 100644 --- a/docs/codegen-options.md +++ b/docs/codegen-options.md @@ -31,7 +31,8 @@ | `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(String,String) | Empty | Use to supply paths to custom FreeMarker templates for code generation. | +| `customTemplatesRoot` | File | Project's dir | Use to supply the path the to custom FreeMarker templates root directory. | +| `customTemplates` | Map(String,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`. | 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 223a88ee..015091d1 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 @@ -54,7 +54,10 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode private Map customTypesMapping = new HashMap<>(); private Map> customAnnotationsMapping = new HashMap<>(); + + private File customTemplatesRoot = null; private Map customTemplates = new HashMap<>(); + private Map> directiveAnnotationsMapping = new HashMap<>(); private String packageName; private String apiPackageName; @@ -136,6 +139,9 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode customTypesMapping != null ? customTypesMapping : new HashMap<>()); mappingConfig.setCustomAnnotationsMapping( customAnnotationsMapping != null ? customAnnotationsMapping : new HashMap<>()); + mappingConfig.setCustomTemplatesRoot( + customTemplatesRoot != null ? customTemplatesRoot : getProject().getProjectDir() + ); mappingConfig.setCustomTemplates( customTemplates != null ? customTemplates : new HashMap<>()); mappingConfig.setDirectiveAnnotationsMapping( @@ -336,6 +342,17 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode this.customTypesMapping = customTypesMapping; } + @InputFile + @Optional + @Override + public File getCustomTemplatesRoot() { + return customTemplatesRoot; + } + + public void setCustomTemplatesRoot(File customTemplatesRoot) { + this.customTemplatesRoot = customTemplatesRoot; + } + @Input @Optional @Override 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 8cc9ec44..aebc8721 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 @@ -65,6 +65,9 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo @Parameter private Map customAnnotationsMapping; + @Parameter + private File customTemplatesRoot; + @Parameter private Map customTemplates; @@ -249,6 +252,7 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo MappingConfig mappingConfig = new MappingConfig(); mappingConfig.setPackageName(packageName); mappingConfig.setCustomTypesMapping(convertToMap(customTypesMapping)); + mappingConfig.setCustomTemplatesRoot(customTemplatesRoot); mappingConfig.setCustomTemplates(customTemplates); mappingConfig.setCustomAnnotationsMapping(convertToListsMap(customAnnotationsMapping)); mappingConfig.setDirectiveAnnotationsMapping(convertToListsMap(directiveAnnotationsMapping)); @@ -739,6 +743,11 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo result.put(name, properties.getProperty(name)); } return result; + } + + @Override + public File getCustomTemplatesRoot() { + return customTemplatesRoot == null ? project.getBasedir() : customTemplatesRoot; } @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 f31cf8a5..fdc72852 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 @@ -43,6 +43,8 @@ trait GraphQLCodegenKeys { val customAnnotationsMapping = settingKey[util.Map[String, util.List[String]]]("customAnnotationsMapping") + val customTemplatesRoot = settingKey[File]("customTemplatesRoot") + val customTemplates = settingKey[util.Map[String, String]]("customTemplates") val generateEqualsAndHashCode = 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 dfa99b93..ff91ea3d 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]](), + customTemplatesRoot := file("."), customTemplates := new JHashMap[String, String](), directiveAnnotationsMapping := new JHashMap[String, JList[String]](), javaxValidationApiVersion := None, @@ -150,6 +151,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.setCustomTemplatesRoot((GraphQLCodegenConfig / customTemplatesRoot).value) mappingConfig.setCustomTemplates((GraphQLCodegenConfig / customTemplates).value) mappingConfig.setGenerateEqualsAndHashCode((GraphQLCodegenConfig / generateEqualsAndHashCode).value) mappingConfig.setGenerateImmutableModels((GraphQLCodegenConfig / generateImmutableModels).value) 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 c15f763c..3c5da2d1 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplateFilesCreator.java @@ -63,8 +63,9 @@ public class FreeMarkerTemplateFilesCreator { if (mappingContext.getCustomTemplates() != null) { templatePath = mappingContext.getCustomTemplates().get(templateType.name()); } + if (templatePath != null) { - return FreeMarkerTemplatesRegistry.getCustomTemplates(templatePath); + return FreeMarkerTemplatesRegistry.getCustomTemplate(mappingContext.getCustomTemplatesRoot(), templatePath); } else { return FreeMarkerTemplatesRegistry.getTemplateWithLang(language, templateType); } 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 f1558d33..bb4b7d83 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplatesRegistry.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/generators/FreeMarkerTemplatesRegistry.java @@ -5,7 +5,6 @@ import com.kobylynskyi.graphql.codegen.model.GeneratedLanguage; import com.kobylynskyi.graphql.codegen.model.exception.UnableToLoadFreeMarkerTemplateException; import freemarker.cache.ClassTemplateLoader; import freemarker.cache.FileTemplateLoader; -import freemarker.cache.MultiTemplateLoader; import freemarker.cache.TemplateLoader; import freemarker.core.PlainTextOutputFormat; import freemarker.ext.beans.BeansWrapper; @@ -28,7 +27,7 @@ class FreeMarkerTemplatesRegistry { new EnumMap<>(GeneratedLanguage.class); private static final Configuration configuration; - + static { try { configuration = buildFreeMarkerTemplateConfiguration(); @@ -64,24 +63,34 @@ class FreeMarkerTemplatesRegistry { templateType.name().toLowerCase()); } - private static Configuration buildFreeMarkerTemplateConfiguration() throws IOException { - Configuration configuration = new Configuration(FREEMARKER_TEMPLATE_VERSION); + private static Configuration buildFreeMarkerTemplateConfiguration() { ClassTemplateLoader classTemplateLoader = new ClassTemplateLoader(GraphQLCodegen.class.getClassLoader(), ""); - FileTemplateLoader fileTemplateLoader = new FileTemplateLoader(new File(".")); - configuration.setTemplateLoader( - new MultiTemplateLoader(new TemplateLoader[] {classTemplateLoader, fileTemplateLoader})); + + return buildFreeMarkerTemplateConfiguration(classTemplateLoader); + } + + private static Configuration buildFreeMarkerTemplateConfiguration(TemplateLoader templateLoader) { + Configuration configuration = new Configuration(FREEMARKER_TEMPLATE_VERSION); + configuration.setTemplateLoader(templateLoader); configuration.setDefaultEncoding(DEFAULT_ENCODING); configuration.setOutputFormat(PlainTextOutputFormat.INSTANCE); configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); configuration.setLogTemplateExceptions(false); configuration.setWrapUncheckedExceptions(true); configuration.setSharedVariable("statics", new BeansWrapper(FREEMARKER_TEMPLATE_VERSION).getStaticModels()); + return configuration; } - public static Template getCustomTemplates(String templatePath) { + private static Configuration buildFreeMarkerCustomTemplateConfiguration(File file) throws IOException { + FileTemplateLoader fileTemplateLoader = new FileTemplateLoader(file); + + return buildFreeMarkerTemplateConfiguration(fileTemplateLoader); + } + + public static Template getCustomTemplate(File templateRoot, String templatePath) { try { - return configuration.getTemplate(templatePath); + return buildFreeMarkerCustomTemplateConfiguration(templateRoot).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 6b37b4fd..1a8863bf 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java @@ -1,6 +1,8 @@ package com.kobylynskyi.graphql.codegen.model; import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType; + +import java.io.File; import java.util.List; import java.util.Map; import java.util.Set; @@ -29,10 +31,17 @@ public interface GraphQLCodegenConfiguration { */ Map getCustomTypesMapping(); + /** + * Can be used to specify the root directory for the custom FreeMaker templates + * + * @return the directory source for the root directory + */ + File getCustomTemplatesRoot(); + /** * Can be used to supply paths to custom FreeMarker templates for code generation. * - * @return a map, where key is a tempalte type and a value is path to a FreeMarker template + * @return a map, where key is a template 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 7faa1dda..93408d4b 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java @@ -1,6 +1,8 @@ package com.kobylynskyi.graphql.codegen.model; import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType; + +import java.io.File; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -86,6 +88,8 @@ public class MappingConfig implements GraphQLCodegenConfiguration, Combinable parametrizedResolverAnnotations = new HashSet<>(); private Map customTypesMapping = new HashMap<>(); + + private File customTemplatesRoot = new File("."); private Map customTemplates = new HashMap<>(); private Set typesAsInterfaces = new HashSet<>(); @@ -247,6 +251,24 @@ public class MappingConfig implements GraphQLCodegenConfiguration, Combinable getCustomTemplates() { + return customTemplates; + } + + public void setCustomTemplates(Map customTemplates) { + this.customTemplates = customTemplates; + } + /** * Provide a path to a custom template for the specific FreeMarker template type (if absent). * @@ -260,15 +282,6 @@ public class MappingConfig implements GraphQLCodegenConfiguration, Combinable 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 9d80bc41..ec12f3c9 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java @@ -84,7 +84,12 @@ public class MappingContext implements GraphQLCodegenConfiguration { public Map getCustomTypesMapping() { return config.getCustomTypesMapping(); } - + + @Override + public File getCustomTemplatesRoot() { + return config.getCustomTemplatesRoot(); + } + @Override public Map getCustomTemplates() { return config.getCustomTemplates(); diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenCustomTemplatesTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenCustomTemplatesTest.java index 0dcf9c3d..1327ce1e 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenCustomTemplatesTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenCustomTemplatesTest.java @@ -36,7 +36,10 @@ class GraphQLCodegenCustomTemplatesTest { @Test void generate_CustomTemplates_Type() throws Exception { - mappingConfig.putCustomTemplatesIfAbsent(FreeMarkerTemplateType.TYPE.name(), "/template/record_type.ftl"); + mappingConfig.putCustomTemplatesIfAbsent( + FreeMarkerTemplateType.TYPE.name(), + "src/test/resources/template/record_type.ftl" + ); generate("src/test/resources/schemas/test.graphqls"); -- GitLab