March 24, 2009

SimpleDateFormat is not thread safe

It has always felt counter intuitive that there are classes which are not thread safe in the Sun JDK, but that is the case. One that I frequently see people trip up on is SimpleDateFormat. From the documentation:

Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.

UPDATE

While SimpleDateFormat is not thread safe, as pointed out in the comments below, Spring seems to create new binders per request removing the need for this approach. In reviewing the documentation it isn't immediately clear that this is the case.

I recently had to create a custom editor for a Spring Web MVC command and ran into this issue. One possible fix, without introducing a ThreadLocal, is to just create a SimpleDateFormat every time. Hence this simple ThreadSafeSimpleDateFormat wrapper.

import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ThreadSafeSimpleDateFormat extends DateFormat {
    private String pattern;

    public ThreadSafeSimpleDateFormat(String pattern) {
        this.pattern = pattern;
    }

    @Override
    public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
        return new SimpleDateFormat(pattern).format(date, toAppendTo, fieldPosition);
    }

    @Override
    public Date parse(String source, ParsePosition pos) {
        return new SimpleDateFormat(pattern).parse(source, pos);
    }
}

Then to setup that as the editor handler for a command that has a date field, in my controller that uses the command I added the following:

@Override
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
    super.initBinder(request, binder);
    binder.registerCustomEditor(Date.class, DATE_TIME, new CustomDateEditor(new ThreadSafeSimpleDateFormat(DATE_TIME_FORMAT), false));
}


Tags: date java spring

March 24, 2009

Velocity and Spring Web MVC

The combination of Spring Web MVC with Velocity makes for easy view handling. One of the things that I'm confused about though is getting the configuration up an running. I've been very happy with this configuration so I thought I'd share it.

First part is to let the system know where to find Velocity templates. I store them all in a directory called velocity which is part of the web application.

<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
    <property name="resourceLoaderPath">
        <value>/WEB-INF/velocity/</value>
    </property>
</bean>

Next up is letting Spring know that Velocity is the default View that will be used. This configures a few handy defaults that represent the common case response. That being is will be an XML response, the template name has no prefix and a .vm suffix, and we configure some custom tools to be available in the macros.

<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
    <property name="exposeSpringMacroHelpers">
        <value>true</value>
    </property>
    <property name="contentType">
        <value>text/xml</value>
    </property>
    <property name="prefix">
        <value></value>
    </property>
    <property name="suffix">
        <value>.vm</value>
    </property>
    <property name="toolboxConfigLocation">
        <value>/WEB-INF/toolbox.xml</value>
    </property>
</bean>

The toolbox configuration file defines some handy tools and in particular defaults the format that dates should be in when converted to a String. In this case the format is what ActionScript 3 expects, since this is the back end for a Flex project.

<toolbox>
    <tool>
        <key>esc</key>
        <scope>application</scope>
        <class>com.neophi.util.NullEscapeTool</class>
    </tool>
    <tool>
        <key>exceptionTool</key>
        <scope>application</scope>
        <class>com.neophi.util.ExceptionTool</class>
    </tool>
    <tool>
        <key>dateTool</key>
        <scope>application</scope>
        <class>org.apache.velocity.tools.generic.DateTool</class>
        <parameter name="format" value="EEE MMM dd HH:mm:ss 'UTC'Z yyyy"/>
    </tool>
</toolbox>

I've always felt like I'm missing some obvious configuration setting with Velocity that will make null values just show up as empty strings instead of being left as $model.attribute. Since I've not found that setting yet, the NullEscapeTool wraps the standard Velocity EscapeTool and sends back an empty string if the value was null.

@Override
public String xml(Object string) {
    String result = super.xml(string);
    if (result == null) {
        return "";
    }
    return result;
}

The ExceptionTool exposes one method stackTrace() that converts the stack trace associated with an exception to a string so that it can be included in the view. Not necessarily something you want to expose in a production environment, but very handy when debugging.

public String stackTrace(Exception exception) {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    PrintStream printStream = new PrintStream(byteArrayOutputStream);
    exception.printStackTrace(printStream);
    printStream.close();
    // Closing a ByteArrayOutputStream has no effect, so don't do it which avoids the need to try/catch the IOException
    return byteArrayOutputStream.toString();
}

Lastly if you want to have Velocity also handle certain exceptions that your web application may throw the exception resolver facility is great for handling that. In this case the exception value that ServerException refers to is a Velocity template that incorporates the ExceptionTool mentioned above.

<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="warnLogCategory">
        <value>com.neophi.exception</value>
    </property>
    <property name="defaultStatusCode">
        <value>200</value>
    </property>
    <property name="exceptionMappings">
        <props>
            <prop key="com.neophi.exception.ServerException">exception</prop>
        </props>
    </property>
</bean>


Tags: configuration java spring velocity

August 27, 2008

Tomcat, Spring Web MVC, and Exceptions

I've been doing some server side development lately and using Spring 2.5.5 with Tomcat 6.0.18. One of the features built in is intelligent exception handling through implementations of HandlerExceptionResolver. In particular there is easy support to "fix" the HTTP response code for errors to be 200 so that Flash doesn't croak. I got my configuration setup but no matter what I did I kept getting back the default Tomcat 500 error page. A little code tracing showed that my configuration was valid and my Velocity based error page was getting picked up and processed but not reflected in the response. Turns out that Spring 2.5.5 and Tomcat 6.0.18 (and earlier versions) don't play well together. A bug has been logged against Spring so that if it generates an error response it clears out the Servlet error request attributes that Tomcat examines to determine if it should return its own built in error page. Alas as of today you'll have to grab a nightly snapshot of Spring to pickup the fix or manually patch DispatcherServlet.java.

Tags: exception java spring tomcat