Access variable of the returning object in Freemarker - freemarker

I have an addNewRow() method that returns a object which gets displayed through the Freemarker template. There is a scenario where I need to check if one of the fields of the returning object has the value of -1. I tried the following syntax unsuccessfully.
<#if ${Object.field} ==-1>
<#if Object.field ==-1>
How can I access the object variable in this case?

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>

FreeMarker Java 8 Optional value support

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()!''}

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)

checking if a map contains a value in Freemarker Template

I'm trying to check if a map contains a value to conditionally execute some freemarker code. This is what I've got so far:
<#if productLayout.layoutWidgetConfiguration[pos.id]??>
<#assign configId>${productLayout.layoutWidgetConfiguration[pos.id]}</#assign>
<#else>
<#assign configId></#assign>
</#if>
But I get this error, which basically fails the if condition.
Error executing FreeMarker template freemarker.core.UnexpectedTypeException: For "...[...]" left-hand operand: Expected a sequence or string (or something that's implicitly convertible to string), but this evaluated to an extended_hash (wrapper: f.t.SimpleHash):
==> productLayout.layoutWidgetConfiguration [in template "admin/pages/catalog/products/partials/productLayoutEditorRefreshZone.ftl" at line 7, column 22]
The failing instruction (print stack trace for 9 more):
==> #if productLayout.layoutWidgetConfigu... [in template "admin/pages/catalog/products/partials/productLayoutEditorRefreshZone.ftl" at line 7, column 17]
at freemarker.core.DynamicKeyName.dealWithNumericalKey(DynamicKeyName.java:141) ~[DynamicKeyName.class:2.3.20]
How can I check if a value exists in a map in a freemarker template?
Update Here:
It seems the hash doesn't like a Long key value if I change it to this, the if check works, but the value doesn't get retrieved even when it exists - so I guess the question now is how to retrieve a value from a hash with a java.lang.Long key?
<#assign configId = "">
<#if productLayout.layoutWidgetConfiguration[pos.id?string]?has_content>
Hello
<#assign configId = productLayout.layoutWidgetConfiguration[pos.id?string]>
</#if>
<h1>${pos.id}</h1>
[] only supports string hash (Map, etc.) keys and numerical sequence (List, array, etc.) indexes. For now the solution is not using [] for Map-s with non-String keys. You can use the Java API of the object instead, like myMap?api.get(nonStringKey), etc. Note that ?api has to be allowed in the configuration; see http://freemarker.org/docs/ref_builtins_expert.html#ref_buitin_api_and_has_api for more.

Access elements by index in an FTL Template

Need to access 1st and 2nd element of a list in the template.
My Java code:
myMap.put("key", Arrays.asList("val1", "val2");
My FTL Template:
<#list myMap?keys as key>
${myMap[key][0]}, ${myMap[key][1]}
<-- the line above fails with undefined expression on myMap[key][0]. I checked and myMap[key] is a SimpleSequence. Also, tried ${myMap[key]?first} and that failed with the same error. Any ideas?
[0] and [1] are fine for this, but it looks like that either the sequence has 0 elements, or those elements are null. What does ${myMap[key]?size} print? BTW, you can write ${myMap[key][0]!'some default'} if you want to get a value even if the item is non-existant or null.
Your problem is that you put the List into your 'myMap' object with the key: "key" then try and access it with they key: "keys".
This is why you were getting an undefined expression, to correct it:
<#list myMap?key as k>
${myMap[k][0]}, ${myMap[k][1]}
or of course you could change your java code to
myMap.put("keys", Arrays.asList("val1", "val2");
and use the ftl code as is.

Resources