Nested directive parameter in Freemarker - java

i'm working with Freemarker in a Java project.
I've defined a custom directive, as #mycustomdirective
Does this custom directive support other directive as parameter?
i.e :
<#mycustomdirective parameter="<#othercustomdirective parameter2="..." />" />
Thanks in advise.

It's not supported; you can only call #function-s and methods inside an expression (be it a parameter value or something else).
This actually has a reason: Directives meant to output markup, and functions/methods are assumed to generate plain text (or numbers, booleans, etc). Thus when you insert an expression with ${exp}, it's subject to auto-escaping (via #escape ATM... so it's "semi-automatic"), while a directive call isn't, so the distinction is important. Parameter values are expressions, so, they meant to be non-markup, and of course, while it's possible to insert non-markup into markup (via escaping), the opposite is fundamentally impossible.
But if you really want to pass around directive-output in expressions, there's hack:
<#assign captured><#myotherdirective /></#assign>
<#mydirective parameter=captured />

Related

When is expression used in mapStruct?

I am getting started with MapStruct. I am unable to understand when do we use "expression" tag in MapStruct? Why do we have certain mappings where we use "target" tag and "expression" tag? Does it mean that expressions are used when you want to map two or more fields within a bean to a single property/field in the target as mentioned in the documentation "http://mapstruct.org/documentation/stable/reference/html/#expressions"
Expressions are used when you can't map a source - to a target property or when a constant does not apply. MapStruct envisioned that several language could be used to address expressions. However, only plain java is implemented (hence "java(... )" ). EL was envisioned but not yet realised.
A typical use case that I use is generating a UUID. But even there you could try the new #Context to achieve that goal.
Remember, the stuff within the brackets is put directly in the generated code. The IDE can't check its correctness, and you will only spot problems during compilation.
Expressions are IMHO a fallback means / gap filler for stuff that is not yet implemented in MapStruct.
Note: Mapping target-to-source by means of a custom method as suggested in the other answers can be done automatically. MapStruct will recognised the signature (return type, source type) and call your custom method. You can do this in the same interface (default method) or in a used mapper.
In general, MapStruct expressions are used when you simple cannot write a MapStruct mapper. They should be used as a fallback approach when the library doesn't apply to your use-case.
For example, -- as the documentation says -- when a mapping requires more than one source variable, an expression can be used to "inject" them to a mapper method.
Another use case is when the source variable you need to use -- say bar -- is not a part of the source class but a member of one of its variables (here, classVar). You would map it to the target field foo using a custom myCustomMethod method with #Mapping(target="foo", expression="java(myCustomMethod(source.classVar.bar)))".

How to handle "Property or field cannot be found on object in SpEL"?

How to handle Property or field <foo> cannot be found on object of type <bar> in SpEL ?
e.g. If data doesn't have placeId property on it then It shouldn't give me above error and return differentValue.
"${#block?.value?.data?.placeId ?: 'differentValue'}"
That's not correct. SpEL is just an another JVM language. It's not non-typed language like JavaScript. So, what is going to happen if your Java class doesn't have some property? Right: Property or field <foo> cannot be found on object of type <bar>.
Therefore a logic in the expression must not rely on some non-Java reflection logic.
You definitely need to have there something like instanceof, but you may live without casting to get access to existing properties.

Lazy evaluation of variables/interpolations for Pebble/Freemarker

Say I have a template in either pebble or freemarker (The two engines I am considering using). It might look something like this:
<Node>
<Element attribute="{{ VAR_A }}"/>
<Element attribute="{{ VAR_F }}"/>
<Element attribute="{{ VAR_N }}"/>
</Node>
In my Java code, I will need to provide an object containing these variables, which I believe can just be a map of variable name to object in both engines.
However to generate the data model, I need to know which variables to calculate values for. I have a lot of data. I don't want to calculate all of VAR_A, VAR_B, VAR_C, VAR_D, VAR_E, etc if they aren't going to be used.
Is there a way in either/both of these engines for getting a list of the required variables before executing the template? A way to do lazy evaluation of each attribute value
Edit: I have no idea what the template will look like when I have to evaluate it as it will be defined by the user. Even the variables they are providing will be user defined strings - which is why I need to get (and analyse) them before I can provide the data.
Each kind of document you generate using Freemarker will have its own template. Each template will have a set if variables it uses. In your Java code you provide a Map that maps variable names to values. If you have a different Java method corresponding to each template, those methods can set up the smallest needed map for that template. That map need not be a HashMap; in theory you could write your own implementation of the Map interface that did lazy evaluation in its get and values (etc) methods. But that is almost certainly more trouble than it is worth. The values in map you provide need not be String objects; Freemarker will use the toString method of each object, which provides a kind of lazy evaluation.

Setting JSP property with JSTL in a nested way?

I have a JSP attribute named "form" set followingly
<c:set value="${fieldAttributeMap[rowId].buildForm}" var="form" />
This works. The attribute "form" contains a Java object, which will used for further evaluation and displaying later in the JSP. However, I would like to use it in a more general way without knowing what the form name is beforehand - it could be named e.g. "modelForm" instead of "buildForm". If we assume that I have stored the name of the variable in JSP attribute "formName"
<c:set value="buildForm" var="formName" />
how can I use this to set the JSP attribute "form" like in the first code example? Basically the expression would have to be evaluated twice, like in this imaginary, non-working example:
<c:set value="${fieldAttributeMap[rowId][${formName}]}" var="form" />
Only workarounds which come to my mind are either writing my own tag or using the antiquated Struts bean:define tag. But I'm hoping there is some better solution or workaround.
Edit: there was a suggestion that this question may be a duplicate of calling another variable using a variable value as parameter in jstl However, the solution offered there is not applicable here, as I need to substitute the name of the attribute as a property of another Java object.
You simply need ${fieldAttributeMap[rowId][formName]}

How do I call java methods on an object from a FreeMarker template?

Is it possible to call a method that takes parameters from a Freemarker template?
I have an object model that I'm trying to render with Freemarker into a web page. One of the objects has a method to get a sublist of it's contents - taking a parameter that is used to filter the list:
public List getunits(final String type);
I know in JSP you can't do this directly, but you can write custom functions that will allow you to achieve the result you want. How do you solve this in Freemarker? Is it the same with writing custom functions? Or is there some way of actually calling this kind of function?
FreeMarker allows invoking methods that were made available through the model from within expressions.
Assuming your object has been exposed as myBean you can invoke the method as follows:
<#list myBean.getunits("myType") as unit>
do stuff with ${unit}
</#list>
You don't have to use <list>, of course, it's just there as an example since your method returns a list.
As ChssPly76 said, you can just peform the method call from within a Freemarker template, as long as you expose the object in the model.
But it's important to keep in mind that if your method returns NULL (for whatever reason), you are going to get a confusing
Expression myBean.getunits() is undefined on line ....
To avoid this, you should better use myBean.getunits(...)! (notice the exclamation point).
Learn more about how Freemarker handles nulls here: http://freemarker.org/docs/dgui_template_exp.html#dgui_template_exp_missing

Categories