Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to supply a root directory with custom templates: "customTemplatesRoot" #1198

Merged
merged 7 commits into from
May 2, 2023
3 changes: 2 additions & 1 deletion docs/codegen-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode

private Map<String, String> customTypesMapping = new HashMap<>();
private Map<String, List<String>> customAnnotationsMapping = new HashMap<>();

private File customTemplatesRoot = null;
private Map<String, String> customTemplates = new HashMap<>();

private Map<String, List<String>> directiveAnnotationsMapping = new HashMap<>();
private String packageName;
private String apiPackageName;
Expand Down Expand Up @@ -136,6 +139,9 @@ public void generate() throws Exception {
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(
Expand Down Expand Up @@ -336,6 +342,17 @@ public void setCustomTypesMapping(Map<String, String> customTypesMapping) {
this.customTypesMapping = customTypesMapping;
}

@InputFile
@Optional
@Override
public File getCustomTemplatesRoot() {
return customTemplatesRoot;
}

public void setCustomTemplatesRoot(File customTemplatesRoot) {
this.customTemplatesRoot = customTemplatesRoot;
}

@Input
@Optional
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
@Parameter
private Map<String, Properties> customAnnotationsMapping;

@Parameter
private File customTemplatesRoot;

@Parameter
private Map<String, String> customTemplates;

Expand Down Expand Up @@ -249,6 +252,7 @@ public void execute() throws MojoExecutionException {
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));
Expand Down Expand Up @@ -739,6 +743,11 @@ private static Map<String, String> convertToMap(Properties properties) {
result.put(name, properties.getProperty(name));
}
return result;
}

@Override
public File getCustomTemplatesRoot() {
return customTemplatesRoot == null ? project.getBasedir() : customTemplatesRoot;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ private static Template getTemplateForTypeAndLanguage(MappingContext mappingCont
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
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;
Expand All @@ -28,7 +27,7 @@ class FreeMarkerTemplatesRegistry {
new EnumMap<>(GeneratedLanguage.class);

private static final Configuration configuration;

static {
try {
configuration = buildFreeMarkerTemplateConfiguration();
Expand Down Expand Up @@ -64,24 +63,34 @@ private static String buildTemplatePath(FreeMarkerTemplateType templateType, Gen
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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -29,10 +31,17 @@ public interface GraphQLCodegenConfiguration {
*/
Map<String, String> 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<String, String> getCustomTemplates();

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -86,6 +88,8 @@ public class MappingConfig implements GraphQLCodegenConfiguration, Combinable<Ma
private Set<String> parametrizedResolverAnnotations = new HashSet<>();

private Map<String, String> customTypesMapping = new HashMap<>();

private File customTemplatesRoot = new File(".");
private Map<String, String> customTemplates = new HashMap<>();

private Set<String> typesAsInterfaces = new HashSet<>();
Expand Down Expand Up @@ -247,6 +251,24 @@ public void setCustomTypesMapping(Map<String, String> customTypesMapping) {
this.customTypesMapping = customTypesMapping;
}

@Override
public File getCustomTemplatesRoot() {
return customTemplatesRoot;
}

public void setCustomTemplatesRoot(File customTemplatesRoot) {
this.customTemplatesRoot = customTemplatesRoot;
}

@Override
public Map<String, String> getCustomTemplates() {
return customTemplates;
}

public void setCustomTemplates(Map<String, String> customTemplates) {
this.customTemplates = customTemplates;
}

/**
* Provide a path to a custom template for the specific FreeMarker template type (if absent).
*
Expand All @@ -260,15 +282,6 @@ public void putCustomTemplatesIfAbsent(String from, String to) {
customTemplates.computeIfAbsent(from, k -> to);
}

@Override
public Map<String, String> getCustomTemplates() {
return customTemplates;
}

public void setCustomTemplates(Map<String, String> customTemplates) {
this.customTemplates = customTemplates;
}

@Override
public Map<String, List<String>> getCustomAnnotationsMapping() {
return customAnnotationsMapping;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,12 @@ public Boolean isGenerateSealedInterfaces() {
public Map<String, String> getCustomTypesMapping() {
return config.getCustomTypesMapping();
}


@Override
public File getCustomTemplatesRoot() {
return config.getCustomTemplatesRoot();
}

@Override
public Map<String, String> getCustomTemplates() {
return config.getCustomTemplates();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ void cleanup() {

@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");

Expand Down