DigitalJoel

2011/03/17

How to create a custom taglib containing an EL function for JSP

Filed under: java — Tags: , — digitaljoel @ 10:49 pm

At some point in your use of JSP, there’s something you’re going to need to do for which you can’t find a spring or jstl tag. In that case, you can create a custom function in your custom tag library. It sounds more difficult than it is. All you will need is a tag library descriptor, and your class that implements the function. That’s about it. Here’s my TLD file.

<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/web-jsptaglibrary_2_0.xsd" 
    version="2.0">

    <tlib-version>2.0</tlib-version>
    <uri>http://www.your-domain.com/taglib</uri>

    <function>
        <name>doMyStuff</name>
        <function-class>com.mydomain.util.ElFunctions</function-class>
        <function-signature>java.lang.String doMyStuff( java.util.Collection )</function-signature>
    </function>
</taglib>

This file should be placed in your WEB-INF directory. In the function-signature, be sure to use fully qualified names.

Next is the class that implements the function.

package com.mydomain.util.ElFunctions;

import java.util.Collection;

/**
 * Functions for use in expression language in the jsp views.
 */
public class ElFunctions
{

    /**
     * This is the function that is called by the Expression Language processor.  It must be static.
     * @param myparam
     * @return
     */
    public static String doMyStuff( Collection<SomeType> myparam )
    {
        // do stuff here and return the results
    }
}

Finally, just reference the function in my jsp file.

<%-- where you declare your taglibs, include this one, which references the tld we created in the first step. --%>

<%@ taglib prefix="my" uri="/WEB-INF/my.tld" %>

<!-- more html and whatever, in my case I'm using spring:message to output the results of my method call -->

<spring:message text="${my:doMyStuff(bean.collection)}" />

The call to ${my:doMytuff(bean.collection)} causes the EL processor to call my function when it evaluates that snippet. In this case, ‘bean’ would be some java bean available to the view, and ‘collection’ would be a property on the bean that returns the collection expected as input to doMyStuff.

2010/12/09

JSP Date Formatting

Filed under: development, java — Tags: , , , — digitaljoel @ 10:58 am

I had an input field that took a date type as mentioned in my previous post. Now the problem was, while I input it in the form MM/dd/yyyy, when I was displaying it on the page for the user to modify, it would come back with time, timezone, all sorts of crap definitely NOT in MM/dd/yyyy format. This caused the form submission to fail unless the user corrected the field every time because date conversion would fail with the huge, lame format.

One wrinkle was that I wanted to support internationalization. While our application currently doesn’t have anything other than en_US right now, I want to make sure I am getting the right date pattern for all instances. So, this is what I did.

<label id="birthday_label" for="birthday" title="<spring:message code="user.birthday.alt" />">
    <spring:message code="user.birthday" />
</label>

<spring:message code="dateFormat" var="dateFormat" />

<input id="birthday" name="birthday" type="text" 
        value="<fmt:formatDate value="${reg.birthday}" 
        type="date" pattern="${dateFormat}" />" />

I have my spring message bundle available, and in that bundle, I have a field called dateFormat which contains the string MM/dd/yyyy. It’s also the field used for doing the date conversion on input. I needed to get the format for use in the fmt:formatDate tag, which is given as the value of the input tag. I’m not a fan of tags within attribute values of tags, but what can you do.

Well, I couldn’t have a tag, in a tag, in an attribute of a tag. Apparently you can only take that so far. So, the trick was using the var of the spring:message to store the dateFormat in something that I could later reference as ${dateFormat} in the pattern of the fmt:formatDate.

2010/11/01

Accessing Spring Session Beans in JSP

Filed under: development — Tags: , , , — digitaljoel @ 5:23 pm

I’m using Spring MVC in a project.  I wanted to create a session scoped bean that I could reference directly from my JSP.  In this case, it was a bean for holding status or error messages for display in the UI.  It would keep a queue of messages, and would clear them when displayed.

The interface for my MessageUtil class was simple, with an addMessage method for adding a message to the queue, and a getFlashMessages method that gets all messages as a list and clears the internal queue.

The implementation could be equally simple.  Mine has a touch more code in order to pull the actual message text from a resource bundle, but the class definition is very simple

public class MessageUtilImpl implements MessageUtil, Serializable
{
// implementation here
}

In my spring context configuration file, I defined the bean as follows:

    <bean id="messageUtil" class="mypackage.MessageUtilImpl" scope="session">
        <aop:scoped-proxy proxy-target-class="false"/>
        <property name="messageSource" ref="messageSource" />
    </bean>

Where the messageSource contains the bundle for messages. The real ticket here is the aop:scoped-proxy configuration.

Since I wanted to inject this message utility class into my Spring MVC controllers (which are of a greater scope than session scope) it was puking at me. Adding aop:scope-proxy configuration to the bean definition (which apparently isn’t available yet as an annotation, which is why I had to configure in xml instead) allows Spring to use AOP to inject the session bean into the controller for the thread that is processing the request, tying my messageUtil to the one that has been constructed for the current session.

One item of note is the proxy-target-class attribute. If you set it to false, then spring aop will use a java interface based proxy. This means that your bean must have an interface and an implementation, and that everywhere you use the bean, you must reference it via the interface and NOT the implementation. Well… DUH. If you have an interface and an impl, and you are referencing the impl, then what can I say? If you set that value to true, then spring aop will use cglib (which now must be on your build path, probably runtime path) to proxy the implementation class, meaning you don’t need to have an interface and implementation, you can simple have a class. I didn’t want to need cglib, so I chose interface based proxy.

With that magic done, now all I had to do was reference my messageUtil bean in the jsps so I could call the getFlashMessages() method and display them.

Now, I’m no JSP guru. I’ve spent the last 3 years in JSF land. I’m sure I could wire this up to get the messages via ajax and do something super awesome… but I didn’t. I’m using the Pines Notify jQuery plugin to show a simple growl-type message.

<script type="text/javascript" >
    <c:forEach var="flashMessage" items="${sessionScope['scopedTarget.messageUtil'].flashMessages}" >
        $.pnotify( {
            pnotify_title: "${flashMessage.title}",
            pnotify_text: "${flashMessage.message}",
            pnotify_type: "${flashMessage.severity}",
            pnotify_shadow: true
        })
    </c:forEach>
</script>

Besides the aop:scoped-proxy, the thing that took the longest to figure out was how to get the stinking spring session bean. You can see that I’m accessing it like this

${sessionScope['scopedTarget.messageUtil'].flashMessages}

The answer is the ‘scopedTarget’ prefix to the bean name. Since it uses a dot in the name, you can’t use sessionScope.scopedTarget.messageUtil, so the way it’s referenced above is the only way I know how to do it. It took surprisingly long for me to find it.

I’m sure as soon as I publish this, someone will find a reference to it in the official spring documentation, but Adobe Reader didn’t find it in the 799 page Spring Documentation PDF I have.

That’s it for this one. Have fun with spring session scoped beans and jsp el.

Create a free website or blog at WordPress.com.