Search code examples
javajspjstlcustom-tagcustom-tags

Defining your own JSP tag body


Recently I've decided to get some knowledge about writing custom tags. And there is a problem.

In my web app I use some JSTL tags and in every JSP page I have got an identical piece of code:

<c:if test="${sessionScope.locale == 'locale_ru_RU' or empty sessionScope.locale}" >
    <fmt:setBundle basename="locale_ru_RU" />
</c:if>
<c:if test="${sessionScope.locale == 'locale_en_US'}">
    <fmt:setBundle basename="locale_en_US" />
</c:if>

As you can see this construction sets correct resource bundle.

So I'd like to know if there is possibility to wrap up this piece of code and use instead of it a single tag (I know there is another way - just put this code in the individual JSP page and use <%@ include %> directive, but I'd like to try a tag)?

As I understand I should someway set body content (inside tag class, not from JSP) and make container to execute it, but I cannot find any examples about it.

What I have got now:

tld:

<?xml version="1.0" encoding="UTF-8"?>
<taglib   xmlns="http://java.sun.com/xml/ns/j2ee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
 http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
 version="2.0">
<tlib-version>1.0</tlib-version>
<tag>
    <name>setLocale</name>
    <tag-class>com.test.tags.LocaleBundleTag</tag-class>
    <body-content>empty</body-content>
</tag>
</taglib>

and my tag:

public class LocaleBundleTag extends BodyTagSupport {

@Override
public void setBodyContent(BodyContent b) {

    try {
        b.clear();
        b.append("<c:if test=\"${sessionScope.locale == 'locale_ru_RU' or empty sessionScope.locale}\" >");
        b.append("<fmt:setBundle basename=\"locale_ru_RU\" />");
        b.append("</c:if>");
        b.append("<c:if test=\"${sessionScope.locale == 'locale_en_US'}\">");
        b.append("<fmt:setBundle basename=\"locale_en_US\" />");
        b.append("</c:if>");
    } catch (IOException e) {
    }

    super.setBodyContent(b);
}
}

It compiles, but does nothing correctly.


Solution

  • No, that won't work, because there's no expectation that the body content will then also be processed by the JSP compiler. Rather you would need to implement the fmt:setBundle yourself within your tag.

    A JSP Tag file would be easier. Operationally it's not that far removed from the include you mentioned, but it makes refactorings like this really trivial.

    I have an extended example here: JSP tricks to make templating easier?