I have a JSP which needs to print some text which is produced by taking loop iterator and feeding it to another object (Spring bean), something like:
<c:forEach var="myVar" items="${myVars}">
<c:out value="anotherObject.getFoo(myVar)"/>
</c:forEach>
Obviously the code above isn't valid as JSTL .
operator only allows parameter-less invocations. I can see following solutions to the problem:
1) Scriptlets
<c:forEach var="myVar" items="${myVars}">
<%
SomeType myVar = (SomeType) pageContext.getAttribute("myVar");
SomeOtherType anotherObject = (SomeOtherType) pageContext.getAttribute("anotherObject");
YetAnotherType result = anotherObject.getFoo(myVar);
pageContext.setAttribute("result", result);
%>
<c:out value="${result}"/>
</c:forEach>
The obvious con here is JSP code pollution and general ugliness.
2) Writing a tag which does whatever is done inside scriptlets. Typical example of over-engineering, yuck!
3) Decompose a collection of myVars
and replace each myVar
with a dynamic proxy, InvocationHandler
of which would add extra parameter-less method to make all getFoo()
calls through anotherObject
. All of that would be done in the controller so JSP would stay clean and myVar
stays the same. But at what price?
I can not add .getFoo()
method to the myVar
because it doesn't fit there and would break the separation of concerns.
It looks like passing parameters will be possible in JSP/EL 2.2, but I'm using Tomcat 6.0.29 which only bundles EL 2.1 API.
Question: can anyone suggest the cleanest approach for this situation?
The initial JSTL 1.0 EL lacked support for functions. The JSP 2.0 EL lets you call a Java class's public static method using the following syntax: ${prefix:methodName(param1, param2, ...)}
Iterating over array using JSTL forEach loop For iterating over an array e.g. String array or integer array in JSP page, "items" attribute must resolved to an array. You can use expression language to get an Array stored in of scope available in JSP e.g. page scope, request scope, session or application scope.
Full Stack Java developer - Java + JSP + Restful WS + Spring The <c:forEach> tag is a commonly used tag because it iterates over a collection of objects. The <c:forTokens> tag is used to break a string into tokens and iterate through each of the tokens.
A simple Java-only "trick-fix" that works in the older JSTL version, too,
and requires no extra taglibs/config/dependencies/frameworks, etc.
is to "wrap" the function you want to call from JSTL
in a class that extends from a Map
class, and override its get()
method.
As a minimal example, if you e.g. want to call the Math.sin()
function from JSTL,
you would define a class:
public class Sine extends HashMap<Double, Double> {
private static final long serialVersionUID = 1L; // Avoids compiler-warning
@Override
public Double get(Object arg) {
Double x = (Double) arg;
return Math.sin(x);
}
}
Then in your Action execute() method, you do:
...
request.setAttribute("sine", new Sine());
...
Then in jsp you can say:
${sine[0.75]}
to calculate the value Math.sin(0.75)
JSTL will treat the variable sine as a Map
, but you can compute and return anything you like from the get() method.
I guess it gets a bit more involved if you have more than one argument to your function, but there should be workarounds for that, too :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With