Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSP expression language and dynamic attribute names

Tags:

java

jsp

jstl

el

I'm trying to do something that seems like it should be relatively straightforward and running into a bit of a wall.

Let's say I've got a list of products which I expose as a request attribute under the name products. Let's also say that each product has an id field, and that I also have a bunch of request attributes set in the form of selectedProduct_<product-id> to indicate which ones are selected.

I understand there are better ways to represent this information, such as placing all the selected ids into a Map and checking against that, but let's assume that I don't have access to that approach for whatever reason.

So what I'd like to do is iterate products and emit some markup only if there is a selectedProduct_... attribute set for the current product. Something like:

<c:forEach var="product" items="${products}">
    <c:if test="${! empty selectedProduct_${product.id}}">
        <div class="productId">${product.id}</div>
    </c:if>
</c:forEach> 

But of course that doesn't work, as it dies on ${! empty selectedProduct_${product.id}}.

What will work is if I hardcode the product-id into the expression, like:

${! empty selectedProduct_17}

...assuming that '17' is a valid product id. Obviously that's not practical, but hopefully it illustrates what I'm trying to accomplish. Basically I need to:

  1. Determine the correct selectedProduct_... value to use for each iteration in the forEach loop. Something as simple as <c:set var="key" value="selectedProduct_${product.id}"/> would do this, except I'm not sure how to then take key and use it to get the value of the request attribute with that name (without cheating and running literal Java code inside a <% %> block).
  2. Get the value of the request attribute whose name I determined in #1. This seems to be the tricky part.

Is this possible using pure JSP/JSTL? I know I could run some Java code inside of <% %> to solve this, but that seems like it would be in exceedingly bad form. Surely a more elegant solution exists?

like image 215
aroth Avatar asked Sep 13 '12 07:09

aroth


1 Answers

You can by using implicit objects:

There are objects that allow access to the various scoped variables described in Using Scope Objects.

  • pageScope: Maps page-scoped variable names to their values
  • requestScope: Maps request-scoped variable names to their values
  • sessionScope: Maps session-scoped variable names to their values
  • applicationScope: Maps application-scoped variable names to their values
When an expression references one of these objects by name, the appropriate object is returned instead of the corresponding attribute. For example, ${pageContext} returns the PageContext object, even if there is an existing pageContext attribute containing some other value.

So, for example:

<c:set var="selectedProductAttrName" value="selectedProduct_${product.id}"/>
${requestScope[selectedProductAttrName]}
like image 132
Jasper de Vries Avatar answered Nov 11 '22 14:11

Jasper de Vries