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?
Depends on the concrete needs, but generally it's somewhat deep water.
The basic stance of FreeMarker is that
nulland 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, maybeuser.fullNameis was oncenullfor someUserobjects, but in the next version there's a class likeSystemUserthat doesn't havegetFullNameat all. Or, same withMap-s, where once the controller hadmap.put('jiraIssue', tracking.jiraIssue), and sometimestracking.jiraIssuewasnull, but in the next versionmap.putis just not called at all in that case. So to keep templates robust, for the template language missing andnullare the same.What you can do is addressing this on the
ObjectWrapperlevel. Instead of the defaultObjectWrapperinstance, you can set your own withConfiguration.setObjectWrapper(ObjectWrapper). You can create aDefaultObectWrapperinstance with itsstrictproperty set totrue, and that will throwInvalidPropertyExceptionif 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 customObjectWrapperimplementation that just returnsnull, but adds the variable name to the set of wrong variable names, which you report after template processing.As of just treating
nullas 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 theObjectWrapperlevel yet again, by returning""with your customObjectWrapperin those cases. You can also use aTemplateExceptionHandler, but that can't provide a default value, it can just replace the whole failing${...}in the output.