In freemarker, can I check if a file exists before it is included?

We are trying to create a system on freemarker, where additional files can be added to replace the blocks of the standard template.

We got to this point

<#attempt> <#include "extension.ftl"> <#recover> Standard output </#attempt> 

So - if the extension.ftl file exists, it will be used, otherwise the part inside the recovery block will be displayed.

The problem is that freemarker always logs the error that caused the recovery unit to fire.

So, we need one of two things:

  • Do not call include if the file does not exist, so check the availability of the file.

-OR -

  1. A way to prevent the registration of errors within the recovery unit without changing the logging to prevent freemarker ALL errors.
+6
freemarker
source share
5 answers

it would be easier:

 <#attempt> <#import xyz.ftl> your_code_here <#recover> </#attempt> 
+2
source share

I had this exact need, but I did not want to use the FreeMarker ObjectConstructor (it looked too much like a scriptlet for my taste).

I wrote a custom FileTemplateLoader :

 public class CustomFileTemplateLoader extends FileTemplateLoader { private static final String STUB_FTL = "/tools/empty.ftl"; public CustomFileTemplateLoader(File baseDir) throws IOException { super(baseDir); } @Override public Object findTemplateSource(String name) throws IOException { Object result = null; if (name.startsWith("optional:")) { result = super.findTemplateSource(name.replace("optional:", "")); if (result == null) { result = super.findTemplateSource(STUB_FTL); } } if (result == null) { result = super.findTemplateSource(name); } return result; } } 

And my corresponding FreeMarker macro:

 <#macro optional_include name> <#include "/optional:" + name> </#macro> 

Requires an empty FTL file ( /tools/empty.ftl ), which contains a comment explaining its existence.

As a result, an β€œoptional” include will include this empty FTL if the requested FTL is not found.

0
source share

We wrote a custom macro that solves this for us. In early testing, it works well. To enable it, add something like this (where mm is Spring ModelMap):

 mm.addAttribute(IncludeIfExistsMacro.MACRO_NAME, new IncludeIfExistsMacro()); 
 import java.io.IOException; import java.util.Map; import org.apache.commons.io.FilenameUtils; import freemarker.cache.TemplateCache; import freemarker.cache.TemplateLoader; import freemarker.core.Environment; import freemarker.template.TemplateDirectiveBody; import freemarker.template.TemplateDirectiveModel; import freemarker.template.TemplateException; import freemarker.template.TemplateModel; /** * This macro optionally includes the template given by path. If the template isn't found, it doesn't * throw an exception; instead it renders the nested content (if any). * * For example: * <@include_if_exists path="module/${behavior}.ftl"> * <#include "default.ftl"> * </@include_if_exists> * * @param path the path of the template to be included if it exists * @param nested (optional) body could be include directive or any other block of code */ public class IncludeIfExistsMacro implements TemplateDirectiveModel { private static final String PATH_PARAM = "path"; public static final String MACRO_NAME = "include_if_exists"; @Override public void execute(Environment environment, Map map, TemplateModel[] templateModel, TemplateDirectiveBody directiveBody) throws TemplateException, IOException { if (! map.containsKey(PATH_PARAM)) { throw new RuntimeException("missing required parameter '" + PATH_PARAM + "' for macro " + MACRO_NAME); } // get the current template parent directory to use when searching for relative paths final String currentTemplateName = environment.getTemplate().getName(); final String currentTemplateDir = FilenameUtils.getPath(currentTemplateName); // look up the path relative to the current working directory (this also works for absolute paths) final String path = map.get(PATH_PARAM).toString(); final String fullTemplatePath = TemplateCache.getFullTemplatePath(environment, currentTemplateDir, path); TemplateLoader templateLoader = environment.getConfiguration().getTemplateLoader(); if (templateLoader.findTemplateSource(fullTemplatePath) != null) { // include the template for the path, if it found environment.include(environment.getTemplateForInclusion(fullTemplatePath, null, true)); } else { // otherwise render the nested content, if there is any if (directiveBody != null) { directiveBody.render(environment.getOut()); } } } } 
0
source share

You can also use the Java method to check if a file exists or not.

Java Method -

 public static boolean checkFileExistance(String filePath){ File tmpDir = new File(filePath); boolean exists = tmpDir.exists(); return exists; } 

Freemarker Code -

 <#assign fileExists = (Static["ClassName"].checkFileExistance("Filename"))?c/> <#if fileExists = "true"> <#include "/home/demo.ftl"/> <#else> <#include "/home/index.ftl"> </#if> 
0
source share

Try this to get the base path:

 <#assign objectConstructor = "freemarker.template.utility.ObjectConstructor"?new()> <#assign file = objectConstructor("java.io.File","")> <#assign path = file.getAbsolutePath()> <script type="text/javascript"> alert("${path?string}"); </script> 

Then this is to navigate the directory structure:

 <#assign objectConstructor = "freemarker.template.utility.ObjectConstructor"?new()> <#assign file = objectConstructor("java.io.File","target/test.ftl")> <#assign exist = file.exists()> <script type="text/javascript"> alert("${exist?string}"); </script> 
-one
source share

All Articles