Search code examples
javajsonfreemarker

Apache Freemarker - How to omit quotes in case of null values for a field in a json?


I have a json template as below:

{
    "firstname": "${fname}"
}

When fname is null, I want to have the value as null instead of a string null ("null"). Hence, I'm expecting the final json to be like:

{
    "firstname": null
}

But, I'm getting:

{
    "firstname": "null"
}

Is there any way we can achieve this using Apache Freemarker? I'm pretty new to Freemarker and couldn't get a precise solution.


Solution

  • Update: Starting from FreeMarker 2.3.32, it's just "firstname": ${fname?cn}. It's important that there are no quotes around the ${...}! This works because if the left-side of ?c/?cn is a string, now instead of failing, it quotes, and escapes it. (Thus you don't even have to know if the left-side is a number/boolean, which must not be quoted, or a string, which must be quoted, as it's automatic.) ?cn is for "?c nullable", means, if the left-side is null/missing value, it prints a null literal (which of course won't be quoted), instead of failing like ?c would. (Also check out the c_format setting for best results, but by default string formatting is JSON compatible, so using ?c/?cn is an improvement without that too.)

    Old answer for 2.3.31

    You could use #if or ?then, and then ?? operator to check if the value is null, but that's verbose. So instead, move the logic into a #function (or into a Java utility method that you expose):

    <#macro nullMarker></#macro>
    <#function jsonString s=nullMarker><#return s?is_macro?then('null', '"${s}"')></#function>
    

    I had to do some ugly hack above, as for a function argument that's null there must be default value. So I can't simply use s?? inside the function, as s inside the function will never be null. So instead, I specified a default value that you surely normally don't want to print as JSON. So now you can do this:

    ${jsonString(fname)}