i am trying to templatise my java class using freemarker.
My config bean is :
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
String[] paths = Stream.of(
"classpath:/templates",
"classpath:/templates/dao/",
"classpath:/templates/pom/",
"classpath:/common/")
.map(path -> path.replace("/", File.separator).replace("\\", File.separator))
.toArray(String[]::new);
configurer.setTemplateLoaderPaths(paths);
configurer.setDefaultEncoding("UTF-8");
configurer.setPostTemplateLoaders();
return configurer;
}
my template file Type.ftl :
<#import "/common/functions.ftl" as function>
<#assign className = "${data.className}">
<#assign typeName = "${function.camelToSnakeCase(data.className)}">
<#assign packagePath = structure.packagePathPrefix + "." + structure.module?replace("-", ".") + ".core.dao.udt">
package ${packagePath};
@Data
@AllArgsConstructor
@NoArgsConstructor(force = true)
@Builder(toBuilder = true)
@UserDefinedType("${typeName}")
public class ${className} {
<#list data.columns as column>
@Column("${column.name}")
private ${column.dataType} ${column.name?uncap_first};
</#list>
}
it works if i refer my function.ftl from currect directory but fails when i refer it from the commons/functions.ftl. i have to use my common functions from /common/functions.ftl so that all templates can use the common functions. But my template gives the following error :
2024-02-27T14:44:54.793-06:00 ERROR 58803 --- [nio-8090-exec-1] freemarker.runtime : Error executing FreeMarker template
freemarker.core._MiscTemplateException: Template importing failed (for parameter value "/common/functions.ftl"):
Template not found for name "common/functions.ftl".
The name was interpreted by this TemplateLoader: MultiTemplateLoader(loader1 = org.springframework.ui.freemarker.SpringTemplateLoader@4f1fb188, loader2 = ClassTemplateLoader(resourceLoaderClass=org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer, basePackagePath="" /* relatively to resourceLoaderClass pkg */)).
----
FTL stack trace ("~" means nesting-related):
- Failed at: #import "/common/functions.ftl" as fu... [in template "dao/udt/Type.ftl" at line 3, column 1]
----
at freemarker.core.LibraryLoad.accept(LibraryLoad.java:67) ~[freemarker-2.3.32.jar:2.3.32]
at freemarker.core.Environment.visit(Environment.java:335) ~[freemarker-2.3.32.jar:2.3.32]
at freemarker.core.Environment.visit(Environment.java:341) ~[freemarker-2.3.32.jar:2.3.32]
at freemarker.core.Environment.process(Environment.java:314) ~[freemarker-2.3.32.jar:2.3.32]
at freemarker.template.Template.process(Template.java:383) ~[freemarker-2.3.32.jar:2.3.32]
at org.springframework.ui.freemarker.FreeMarkerTemplateUtils.processTemplateIntoString(FreeMarkerTemplateUtils.java:50) ~[spring-context-support-6.1.3.jar:6.1.3]
i tried relative path like :
<#import "../../../common/functions.ftl" as function>
but u get error again :
2024-02-27T14:55:44.552-06:00 ERROR 60233 --- [nio-8090-exec-1] freemarker.runtime : Error executing FreeMarker template
freemarker.core._MiscTemplateException: Template importing failed (for parameter value "../../../common/functions.ftl"):
Template not found for name "dao/udt/../../../common/functions.ftl".
Reason given: Backing out from the root directory is not allowed.
The name was interpreted by this TemplateLoader: MultiTemplateLoader(loader1 = FileTemplateLoader(baseDir="/Users/rahulverma/git/by-rahul/one-click-code/template-services-code-core/target/classes/templates", canonicalBasePath="/Users/rahulverma/git/by-rahul/one-click-code/template-services-code-core/target/classes/templates/"), loader2 = FileTemplateLoader(baseDir="/Users/rahulverma/git/by-rahul/one-click-code/template-services-code-core/target/classes/templates/dao", canonicalBasePath="/Users/rahulverma/git/by-rahul/one-click-code/template-services-code-core/target/classes/templates/dao/"), loader3 = FileTemplateLoader(baseDir="/Users/rahulverma/git/by-rahul/one-click-code/template-services-code-core/target/classes/templates/pom", canonicalBasePath="/Users/rahulverma/git/by-rahul/one-click-code/template-services-code-core/target/classes/templates/pom/"), loader4 = FileTemplateLoader(baseDir="/Users/rahulverma/git/by-rahul/one-click-code/template-services-code-core/target/classes/common", canonicalBasePath="/Users/rahulverma/git/by-rahul/one-click-code/template-services-code-core/target/classes/common/"), loader5 = ClassTemplateLoader(resourceLoaderClass=org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer, basePackagePath="" /* relatively to resourceLoaderClass pkg */)).
appreciate any thoughts on how to resolve this?
edit :
i have this final multi module project(in cyan lines) in which i collect template path of each module as a bean(pink lines) and finally inject it in the configuration. (pink lines)
i am expecting the function.ftl template having functions/macro to import in EntityTemplate.ftl. (yellow lines) please note that the function.ftl is altogether in a different package than EntityTemplate.ftl. Is this functionality achievable in freeMarker that i can import common functions in my other modules ? if yes how can i achieve this ? i tries giving a template /common in the classpath so that template engine can search it but it could not and throw a template not found exception . any thoughts on how to achieve this ? currently i have to add functions.ftl to each directory as it is only able to discover the .ftl files locally.
With "classpath:/templates", "classpath:/templates/dao/", "classpath:/templates/pom/", "classpath:/common/"
, you specify template root directories. That is all files inside "dao" will appear on the top level as far as FreeMarker templates see it.
So you should simply have "classpath:/templates"
, and then put commons
inside that. Of course you can place commons
elsewhere too, but then you have to give its parent directory in the template loader path.
Tip: You can use ${current_template_name}
to understand what the current template name (path) is.