I discover jsp tags recently and use them to avoid duplication of common part of my views.
So in my JSP views I have
<web-component:mytag>
<!-- HTML specific to that page -->
</web-component:mytag>
And in my tag file I get the HTML with <jsp:doBody/>
.
My question is, how can I test if <jsp:doBody/>
is empty so I can put a default HTML content?
Something like
<c:choose>
<c:when test="${!doBody.empty}">
<jsp:doBody/>
</c:when>
<c:otherwise>
<!-- My default HTML content here -->
</c:otherwise>
</c:choose>
So I'm looking for the correct expression insted of doBody.empty
Thanks in advance.
You have three options available to you, each with its pros and cons.
<jsp:doBody var="bodyText" />
This is probably the most common and obvious solution.
You execute the body once, store its output in a variable, and check to see if that variable is empty.
<jsp:doBody var="bodyText"/>
<c:choose>
<c:when test="${not empty fn:trim(bodyText)}">
${bodyText}
</c:when>
<c:otherwise>
<!-- Default content here -->
</c:otherwise>
</c:choose>
Why use
${not empty fn:trim(bodyText)}
instead of the simpler condition${empty bodyText}
? Thanks to @ach, who pointed this out, the latter trims whitespace and thus behaves consistently regardless of thetrimDirectiveWhitespaces
setting.
The body always gets executed. You may not want to execute the tag body (and any side effects) just to test for its existence.
The entire contents of the tag body get stored in memory. This could be an issue for longer tag bodies.
(Disregard this point when using ${not empty fn:trim(bodyText)}
. It only applies to ${empty bodyText}
.)
Whether the condition ${empty bodyText}
is true or not depends on whether the calling JSP enables trimDirectiveWhitespaces
.
When the tag's body contains nothing but whitespace
<%@ page trimDirectiveWhitespaces="true" %>
<my:tag value="a">
</my:tag>
and the page defines trimDirectiveWhitespaces="true"
, your tag file will detect that there is no body. If trimDirectiveWhitespaces="false"
, your tag file will detect that there is a body.
Note that this only applies to tag files, not simple/classic tag handlers. In the above example, if <my:tag>
were defined in a tag handler, the handler would behave as if a body exists regardless of the whitespace setting:
getJspBody()
would be non-null.doAfterBody()
would be called.You can do away with the cons of the first solution by testing for null body with Java code. This solution and the next do exactly that, except this one is simpler and uses a scriptlet.
<c:choose>
<c:when test="<%= super.getJspBody() != null %>">
<jsp:doBody />
</c:when>
<c:otherwise>
<!-- My default HTML content here -->
</c:otherwise>
</c:choose>
The reason this works is that tag files are translated into handlers extending SimpleTagSupport
(see javax.servlet.jsp.tagext) and scriptlets are executed within the handler's doTag()
method. Thus super.getJspBody() == null
works the same as you'd expect in any simple tag handler.
The test for a null body is done without executing the body.
The body is not stored in a variable.
scripting-invalid
configuration for JSP files.)And if you need the functionality of the scriptlet solution without actually using scriptlets, read on.
The idea here is to encapsulate the body null test within a tag handler called from the tag file. The tag handler can get access to the tag file via getParent()
and and export the boolean test result as a variable:
class HasBody extends SimpleTag {
@Override
public void doTag() throws JspException {
TagAdapter adapter = (TagAdapter)this.getParent();
SimpleTagSupport parent = (SimpleTagSupport)adapter.getAdaptee();
// `getJspBody()` is a protected method, so actually you must use reflection.
JspFragment body = parent.getJspBody();
this.getJspContext().setAttribute("hasBody", body == null);
}
}
Now your tag file can look like this:
<my:hasBody />
<c:choose>
<c:when test="${hasBody}">
<jsp:doBody />
</c:when>
<c:otherwise>
<!-- Default content here -->
</c:otherwise>
</c:choose>
@Ryan was wondering about adapting this approach to general JSPFragment
attributes. Luckily, because all attributes are directly accessible as variables from EL (whereas the body is not), testing for an empty fragment attribute is trivial:
<%@ attribute name="frag" fragment="true" %>
<c:choose>
<c:when test="${frag != null}">
<jsp:invoke fragment="frag" />
</c:when>
<c:otherwise>
<!-- Default content here -->
</c:otherwise>
</c:choose>
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