Calling a method with a parameter inside a JSTL loop

I have a JSP that needs to print some text that is created using a loop iterator and feed it to another object (Spring bean), something like:

<c:forEach var="myVar" items="${myVars}"> <c:out value="anotherObject.getFoo(myVar)"/> </c:forEach> 

Obviously, the above code is invalid because the JSTL statement . allows only calls without parameters. I see the following solutions to the problem:

1) Scripts

 <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 point here is JSP code pollution and general ugliness.

2) Writing a tag that does everything that is done inside the scriptlets. A typical example of over engineering, yuck!

3) Expand the myVars collection and replace each myVar with a dynamic proxy whose InvocationHandler will add an extra-less parameter to make all getFoo() calls through anotherObject . All this will be done in the controller, so the JSP will remain clean and myVar will remain the same. But at what price?

I cannot add the .getFoo() method to myVar because it does not fit and breaks the separation of problems.

It seems that the transfer parameters will be possible in JSP / EL 2.2, but I am using Tomcat 6.0.29, which only binds the EL 2.1 API.

Question: can anyone suggest the cleanest approach for this situation?

+7
source share
6 answers

Here is how I did it at the end.

Instead of passing a collection of SomeType instances SomeType I am passing a map. The card keys are the same SomeType , and the values ​​are instances of the controller-specific internal class, let it be SomeTypeSupplement .

SomeTypeSupplement adds the necessary non-arg getters and wires all together. JSP now iterates over map entries and can retrieve data via JSTL.

Thus, I avoid the magic of Proxy , unnecessary TLDs, keep the JSP in order and reasonably safe type.

+2
source

Simple Java-only "trick-fix", which also works in the old version of JSTL, and does not require additional taglibs / config / dependencies / frameworks, etc. is to "wrap" the function that you want to call from JSTL in a class that extends from the Map class and overrides its get() method.

As a minimal example, if you, for example, 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 execution method () you will execute:

 ... request.setAttribute("sine", new Sine()); ... 

Then in jsp you can say:

  ${sine[0.75]} 

to calculate the value of Math.sin(0.75)

JSTL will treat the sine variable as Map , but you can compute and return whatever you like from the get () method.

I think this becomes a little more attractive if you have several arguments for your function, but there must also be workarounds for this :)

+7
source

If you cannot execute scriptlets (your option 1), I would create for it my own tag (your alternative option 2) or a custom EL function. I do not agree that this is "excessive," using the available tools as intended.

Your alternative 3, however, I do not like. In any case, this supertechnology plus it will make your system unnecessarily complicated and complicated for other people. Observe the intentions of the specifications and standards in which you operate. Do not make it harder or harder.

+1
source

Why not just make a list of objects in your base Java code and then just use the JSP to display it?

+1
source

I wanted to add a comment to the last (in time) Rop answer, but there is no "reputation", so here I am with the answer.

Soon I got the same idea with such a map, but tried to make it more accessible by using the DynamicMap, DynamicMapCalculator interface and allowing you to wrap any method call on such a map (without having to create a new map implementation each time, just using an anonymous instance class).

This will be the topic if you are interested: A qu. style: JSTL dynamic map breaks work with missing parameter function calls

And I would be interested in opinions: is this what you can do without a bad conscience?

+1
source

Another option is to use Velocity . This is much better than jstl.

0
source

All Articles