Stack Exchange
Custom TemplateExceptionHandler
I need to change the FreeMarker behavior about processing template&data in case some data are missing.
In missing case I need to let the template unchanged and continue in processing.
Example:
Template:
... 
var1 = ${var1} 
var2 = ${var2} 
...

Data:
var1 = Hello

I need Result after processing:
...
var1 = Hello
var2 = ${var2}
...

My solution is:
class MyTemplateExceptionHandler implements TemplateExceptionHandler {
    public void handleTemplateException(TemplateException te, Environment env, java.io.Writer out)
            throws TemplateException {
        try {
            //2nd word on 2nd row is name of missing variable :(
            String missingVariable = te.getMessageWithoutStackTop().split("\n")[1].split(" ")[1];
            out.write("${" + missingVariable + "}");
        } catch (IOException e) {
            throw new TemplateException("Failed to print error message. Cause: " + e, env);
        }
    } }

and using:
...
Configuration cfg = new Configuration();
cfg.setTemplateExceptionHandler(new MyTemplateExceptionHandler());
...

My solution works, but I am not satisfied because of:
1) getting missing variable in handleTemplateException() is horrible. Does exist better way how to get a name of missing variable?
2) Even if I have my own TemplateExceptionHandler, FreeMarker writes enough information to output. Can I change it?
Example output for missing variable "environment_name":
22.10.2014 9:01:55 freemarker.log._JDK14LoggerFactory$JDK14Logger error
SEVERE: Error executing FreeMarker template
FreeMarker template error:
The following has evaluated to null or missing:
==> environment_name  [in template "Osb-PrepareAndDeploy.ftl" at line 33, column 33]

Tip: If the failing expression is known to be legally null/missing, either specify a default value with myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthessis: (myOptionVar.foo)!myDefault, (myOptionVar.foo)??

The failing instruction (FTL stack trace):
----------
==> ${environment_name}  [in template "Osb-PrepareAndDeploy.ftl" at line 33, column 31]
----------

Java stack trace (for programmers):
----------
freemarker.core.InvalidReferenceException: [... Exception message was already printed; see it above ...]
    at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:98)
    at freemarker.core.EvalUtil.coerceModelToString(EvalUtil.java:382)
    at freemarker.core.Expression.evalAndCoerceToString(Expression.java:115)
    at freemarker.core.DollarVariable.accept(DollarVariable.java:76)
    at freemarker.core.Environment.visit(Environment.java:265)
    at freemarker.core.MixedContent.accept(MixedContent.java:93)
    at freemarker.core.Environment.visit(Environment.java:265)
    at freemarker.core.Environment.process(Environment.java:243)
    at freemarker.template.Template.process(Template.java:277)
    at net.homecredit.scm.jenkinsTool.countrySettings.Country.createJobs(Country.java:282)
    at net.homecredit.scm.jenkinsTool.Start.main(Start.java:83)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)


You can't prevent the exception from being logged. TemplateExceptionHandler doesn't mean to make non-error from an error, it just lets you decide what to do after the error has happened. Like, you want to print an error page or something. In extreme case, you may want to continue page rendering after printing some error indicator, but that's still an error that need to be fixed.
Maybe it would help if you tell why do you need this. Maybe the solution isn't TemplateExceptionHandler-s.
As of more intelligent exception processing, first, in the handler you should check if the exception is a InvalidReferenceException, becaue I guess you don't want to deal with others. Then, with getBlamedExpressionString() (requires FreeMarker 2.3.21) you could get part of what you want to print to the output. It's only part of that, because if ${x + 1} fails because x is undefined, it will only return "x", not "x + 1".

I would like to use FreeMarker to prepare a template to create a Jenkins job (which use parameters). Jenkins use substitution format ${} - the same as FreeMarker.
I have a XML template (for Jenkins job) with a few places to substitution, but some of them I need to change via FreeMarker but some of them I don't want to substitute because those are for Jenkins.
Is a way to change FreeMarker substitution format from ${}?

So in that case you indeed should change the substitution syntax of one of the participants. You can't configure the syntax of FreeMarker (at least in 2.3.x). But you can write a TemplateLoader that wraps another TemplateLoader (your current one) and transforms the text that it gets. So, you could transform all %{...}-s to ${...}, and all ${...}-s to %{...}, and then back again in the output Writer. I know, painful, but that's a far less dirty hack than suppressing undefined variable errors, etc.

I changed FreeMarker by Velocity. My requested behavior is default for Velocity.
