Handle Null or Missing Values in FreeMarker

162 views Asked by At

How to distinguish the null values from the missing one. I'm getting the following Java error:

freemarker.core.InvalidReferenceException: The following has evaluated to null or missing

Objective: I'm using TemplateExceptionHandler to write the missing variables in red and want to generate empty text for null values. The exception is raised for both missing and null values as they are equivalent. Is there any solution to this issue?

1

There are 1 answers

3
ddekany On

Depends on the concrete needs, but generally it's somewhat deep water.

The basic stance of FreeMarker is that null and missing are these same for templates, because in practice those who provide the model (the template context, the variables) often aren't consistent in this regard, especially over time. Like, maybe user.fullName is was once null for some User objects, but in the next version there's a class like SystemUser that doesn't have getFullName at all. Or, same with Map-s, where once the controller had map.put('jiraIssue', tracking.jiraIssue), and sometimes tracking.jiraIssue was null, but in the next version map.put is just not called at all in that case. So to keep templates robust, for the template language missing and null are the same.

What you can do is addressing this on the ObjectWrapper level. Instead of the default ObjectWrapper instance, you can set your own with Configuration.setObjectWrapper(ObjectWrapper). You can create a DefaultObectWrapper instance with its strict property set to true, and that will throw InvalidPropertyException if you refer to an non-existent Java bean property. That you can't handle in template, so the template will fail, and you can catch the exception and report the issue. Or, you can create a custom ObjectWrapper implementation that just returns null, but adds the variable name to the set of wrong variable names, which you report after template processing.

As of just treating null as empty string, yet again the template language is quite opinioned, and wants you to put a ! after the variable name to explicitly handle the situation. But you can address this on the ObjectWrapper level yet again, by returning "" with your custom ObjectWrapper in those cases. You can also use a TemplateExceptionHandler, but that can't provide a default value, it can just replace the whole failing ${...} in the output.