FreeMarker Java 8 Optional value support - java-8

Does FreeMarker support Optional value in Java 8?
e.g. I have String id, and its getter method is like:
public Optional<String> getId() {
return Optional.ofNullable(Id);
}
How am I going to reference it in the .ftl file. It seems that {data.id} can not find the correct Optional value. But gives me Optional[1334586]

Well, Freemarker is not supposed to be aware of Optional or it is better to say that its dynamically typed so it works for any object.
Since you calling ${data.id} it's just calls toString on Optional which is totally expected behavior.
If you want to handle null values in your template and for that you want to use Optional, you may choose to set a default value if null, so Optional usage won't be needed:
Synopsis: unsafe_expr!default_expr or unsafe_expr! or (unsafe_expr)!default_expr or (unsafe_expr)!
Example: ${data.id!"No id."}
Or check if it's exists:
<#if data?? && data.id??>
Id found
<#else>
Id not found
</#if>
For more info check out the Freemarker docs. Specifically parts: Handling missing values and Missing value test operator.
If you just want to get the value from Optional in your template:
${data.id.orElse('')}
or
${data.id.get()!''}

Related

Problem detecting and using a nullable value in Freemarker

I have a POJO object that I have serialized from JSON (in Java). I am using an object wrapper constructed via:
DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_27);
builder.setExposeFields(true);
objectWrapper = builder.build();
I use the setExposeFields(true) because the object I am wrapping is not a Java bean, but rather just a POJO that contains public fields.
I am doing the following in my template:
<#ConditionOccurrence co = c/>
<#macro ConditionOccurrence co>
<#list co?keys as key>
${key}
</#list>
${co.occurrenceStartDate!'wtf'}
${co["occurrenceStartDate"]}
A condition occurrence of: ${codesetName(co.codesetId, "any condition")}
<#if co.first!false>- for the first time in the person's history</#if>
<#if (co["occurrenceStartDate"])??>co.OSD is null: </#if>
</#macro>
Note, the 'c' is an element in a sequence, and is not important to the exact problem I am having.
The output of the template shows this:
stopReason
getClass
gender
CorrelatedCriteria
providerSpecialty
occurrenceStartDate
occurrenceEndDate
visitType
accept
codesetId
hashCode
conditionSourceConcept
equals
conditionType
toString
conditionTypeExclude
class
first
age
org.ohdsi.circe.cohortdefinition.DateRange#68e62ca4
org.ohdsi.circe.cohortdefinition.DateRange#68e62ca4
A condition occurrence of: Psoriasis
- for the first time in the person's history
co.OSD is null:
The first set of lines are all the keys in my POJO. This is correct.
the two lines of output:
org.ohdsi.circe.cohortdefinition.DateRange#68e62ca4
org.ohdsi.circe.cohortdefinition.DateRange#68e62ca4
This is showing that the field occurrenceStartDate is an object of type DateRange. note this could be null in some cases, so I am checking how to check for null...
The next part of the output:
- for the first time in the person's history
co.OSD is null:
This is showing that it is reading the 'first' attribute of the object correctly, and I have switched the raw JSON from 'true' to 'false' and the template responds properly to the change in this value. Note, in the object, the 'first' field is type Boolean.
The second line: co.OSD is null is what is confounding me. I confirmed earlier that outputting the 'occurrenceStartDate' field shows that it holds a DateRange object. But, this statement is evaluating to TRUE (ie: it is null):
#if (co["occurrenceStartDate"])??>co.OSD is null: </#if>
I have tried with both dot notation and bracket notation. For some reason, the ?? operator on that field is saying it is null. Note, the underlying object isn't a simple String or Number type, it is a simple POJO class DateRange with 3 String properties on it. Again, these are not JavaBeans, these are just POJOs.
Can anyone explain why the ?? operator says it is empty when it is clearly referencing an object? Btw: if I attempt to access co.occurrenceStartDate at all, it results in a template error that I'm referencing a null value, so the core problem here is why does the wrapper thing it is a null?
Thank you in advance for your help.
The ?? operator means "is present", not "is missing". So your line should be:
<#if !(co.occurrenceStartDate??)>co.OSD is null: </#if>

Compare String with Spring Security tag using Freemarker

How can I achieve the following with Freemarker and Spring Security taglibs?
<#if "[]" == <#security.authentication property='principal.userAccount.administratedVendors'/> >
My Accounts
</#if>
Currently, the above doesn't compile.
The root of here problem is that security.authentication shouldn't be a FreeMarker directive, but a FreeMarker function or method. Directives don't have a return value (therefore you can't use them in place of an expression, like you did). Directives can print to the output (among others), but that's just a "side effect", not a return value. FreeMarker functions/methods have a return value. But if the Spring integration doesn't provide the same call as function/method (check that), then the best you can do is this ugly workaround:
<#assign capturedOutput><#security.authentication property='principal.userAccount.administratedVendors'/></#assign>
<#if capturedOutput == '[]'>
My Accounts
</#if>
It's bit fragile in theory, as (I guess) principal.userAccount just prints the toString() of the property value object. While for most List implementations that will return "[]" for an empty list,, it's not guaranteed by the Java API.

Assigning empty string if XML node doesn't exist in Freemarker

I have an XML document passed as root to a Freemarker template. I want some values from this XML to be assigned to variables as a string and later concatenate/print them out.
<#assign MyVar = root.child1.child2.child3.mynode>
The issue here is that even when a path doesn't exist MyVar gets assigned with a sequence+hash which cannot be printed out or converted to string. This variable although returns false for ?has_content, it needs an extra step for these checks and I have this same issue with many variables and across template files and modules.
The only solution I have been able to find was
<#assign MyVar = root.child1.child2.child3.mynode>
<#assign MyVar = MyVar ?has_content?then(MyVar , "")>
I am looking for something like the Default Value Operator which also checks for nulls like ?has_content.
Does Freemarker provide any simpler one line function to check if a variable has no content and assign it with a default?
In short:
<#assign myVar = root.child1.child2.child3.mynode[0]!''>
Or just <#assign myVar = root.child1.child2.child3.mynode[0]!> if the implicit multi-typed default value doesn't cause problems (like when you just print it with ${}).
Why: XML queries (just like XPath queries) always return a sequence of matching nodes. There are maybe 0 such nodes (or 1, or multiple). An empty sequence is not a "missing value" according the template language. It's an inconvenient mismatch with the XML data-model. But while the sequence always exists, its 1st element ([0]) doesn't, so you can use all the missing value handler operators with it as usual.

How can I set a FreeMarker variable with an interpolated value? error: "You can't use "${" here as you are already in FreeMarker-expression-mode."?

I am absolutly new in FreeMarker and I have the following problem working on a Spring MVC application that use this template engine.
So into a controller method I put an int representing the current year (2016) into the model, in this way:
model.addAttribute("annoCorrente", annoCorrente);
Then, into my FreeMarker page I have to assign this value to a variable, so I write the following expression:
<#assign a = ${annoCorrente}>
But in this way I obtain the following error message:
[col. 86] You can't use "${" here as you are already in FreeMarker-expression-mode. Thus, instead of ${myExpression}, just write myExpression. (${...} is only needed where otherwise static text is expected, i.e, outside FreeMarker tags and ${...}-s.)
Why? How can I correctly initizialize a FreeMarker variable with the value obtained from the model associated to this view?
Change <#assign a = ${annoCorrente}> to <#assign a = annoCorrente>
(or you can do <#assign a = "${annoCorrente}"> but this is not recommended)

WebApi Odata string parameters - how to get rid of the ' for functions?

I am a little lost here.
Given the following method:
[ODataRoute("MktInstrument(Symbol={symbol})")]
public MktInstrument MktInstrument(string symbol) {
I call it using a URL in the form of:
http://localhost/MktInstrument(Symbol='FOREX!EURxUSD')
That is nice - but the variable symbol now includes the ' that wrap the parameter.
if I put that into the template
[ODataRoute("MktInstrument(Symbol='{symbol}')")]
I get an error that the template is not valid.
If I call it witout the warapping
http://localhost/MktInstrument(Symbol=FOREX!EURxUSD)
then the method is not called. Am I really supposed to remove the '' around the string parameter myself or am I missing something?
In your controller, you can make the action method like "public IHttpActionResult Function([FromODataUri]string symbol)" which means you add attribute [FromODataUri], it will not have single quotes. You can refer to http://odata.github.io/WebApi/#04-06-function-parameter-support, the related statement is
‘[FromODataUri]’ is mandatory for complex, entity and all collection. However, it is optional for Primitive & Enum. But for string primitive type, the value will contain single quotes without ‘[FromODataUri]’.

Resources