45

I have some classes which extends a superclass, and in the JSP I want to show some attributes of these classes. I only want to make one JSP, but I don't know in advance if the object has an attribute or not. So I need a JSTL expression or a tag which checks that the object I pass has this attribute (similar to in operator in javascript, but in the server).

<c:if test="${an expression which checks if myAttribute exists in myObject}">
    <!-- Display this only when myObject has the atttribute "myAttribute" -->
    <!-- Now I can access safely to "myAttribute" -->
    ${myObject.myAttribute}
</C:if>

How can I get this?

Thanks.

Javi
  • 19,387
  • 30
  • 102
  • 135

5 Answers5

64

Make use of JSTL c:catch.

<c:catch var="exception">${myObject.myAttribute}</c:catch>
<c:if test="${not empty exception}">Attribute not available.</c:if>
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 35
    Is it just me? I think this is an ugly way to see if a variable exists or not. Its like catching NullPointerException in java instead of ? `(if!=null)` – Shervin Asgari May 23 '12 at 12:49
  • 8
    @Shervin: it's indeed a bad design. But that's so far the only way to achieve the odd requirement. – BalusC May 23 '12 at 12:53
  • @Shervin Asgari I think "if null" are ugly. Unless you do it third party api. you should take care of all exception - way cleaner. – magulla Oct 26 '16 at 19:05
  • @ShervinAsgari - You are correct, however it's often the case with JSP/JSTL that 'pretty' solutions are either unavailable, verbose, or extremely circuitous (see sbk's answer, which creates an _entire new taglib_). Trying to do a proper `if/else-if` block is another good example of this. – aroth May 16 '17 at 04:58
  • if you want to check list attribute is null, use `${list != null}` because `${not empty list}` return true when list is empty list. – SHRIN Apr 20 '18 at 08:05
  • @BalucS: sorry i confused. – SHRIN Apr 21 '18 at 08:47
16

You can readily create a custom function to check for the property, as per vivin's blog post.

In short, if you already have your own taglib its just a matter of creating a static 'hasProperty' method...

import java.beans.PropertyDescriptor;
import org.apache.commons.beanutils.PropertyUtils;

...

public static boolean hasProperty(Object o, String propertyName) {
    if (o == null || propertyName == null) {
        return false;
    }
    try
    {
      return PropertyUtils.getPropertyDescriptor(o, propertyName) != null;
    }
    catch (Exception e)
    {
      return false;
    }
}

...and adding five lines to your TLD...

<function>
    <name>hasProperty</name>
    <function-class>my.package.MyUtilClass</function-class>
    <function-signature>boolean hasProperty(java.lang.Object,
        java.lang.String)
    </function-signature>
</function>

... and calling it in your JSP

<c:if test="${myTld:hasProperty(myObject, 'myAttribute')}">
  <c:set var="foo" value="${myObject.myAttribute}" />
</c:if>
sbk
  • 3,856
  • 1
  • 19
  • 19
5

The accepted answer may have some side effects when I just want to test if the object has a field, but do not want to output the value of the field. In the mentioned case, I use the snippet below:

 <c:catch var="exception">
        <c:if test="${object.class.getDeclaredField(field) ne null}">            
        </c:if>
 </c:catch>

hope this helps.

lin
  • 1,425
  • 1
  • 19
  • 27
3

Just a more detailed (typical?) usage of BalusC great answer

<%--
  [1] sets a default value for variable "currentAttribute"
  [2] check if myObject is not null
  [3] sets variable "currentAttribute" to the value of what it contains
  [4] catches "property not found exception" if any
       - if exception thrown, it does not output anything
       - if not exception thrown, it outputs the value of myObject.myAttribute

--%>
<c:set var="currentAttribute" value="" /> <%-- [1] --%>
<c:if test="${not empty myObject}"> <%-- [2] --%>
    <c:set var="currentAttribute"> <%-- [3] --%>
        <c:catch var="exception">${myObject.myAttribute}</c:catch> <%-- [4] --%>
    </c:set>
</c:if>

<%-- use the "currentAttribute" variable without worry in the rest of the code --%>
currentAttribute is now equal to: ${currentAttribute}

As pointed out by Shervin in the comments of BalusC's answer, this is probably NOT the cleanest solution but as replied by BalusC "that's so far the only way to achieve the odd requirement".

Resources

Community
  • 1
  • 1
Adriano
  • 19,463
  • 19
  • 103
  • 140
0

Do you mean something like this:

<c:if test="${not null myObject.myAttribute}">
   <!-- Now I can access safely to "myAttribute" -->
</C:if>

or other variant

<c:if test="${myObject.myAttribute != null}">
   <!-- Now I can access safely to "myAttribute" -->
</C:if>

If it is a list you can do

<c:if test="#{not empty myObject.myAttribute}">
Shervin Asgari
  • 23,901
  • 30
  • 103
  • 143
  • 3
    No, if I do myObject.myAttribute and myObject has not a getter for myAttribute I'll get a PropertyNotFoundException. It's not the same that an object has a property with null value that it doesn't have this property. – Javi Mar 26 '10 at 10:50
  • But how else are you supposed to access the property? It can only be access through getters as far as I know. Even if the variable is public I believe you need a getter. Why cant you just create a getter? – Shervin Asgari Mar 29 '10 at 07:45
  • 4
    The property is not present in every subclass, so when the property is present I have a getter for it. The problem is that I don't know which of the subclasses is going to be passed. – Javi Mar 29 '10 at 14:52
  • @Shervin I believe your answer is "only" checking if the attribute is set (not null and not an empty string) – Adriano Oct 01 '14 at 08:33