Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSF custom Converter for Date - Is is thread safe?

I have created a custom Converter in JSF 1.2 to convert Date objects. The dates have a very particular format. I have implemented my converter using the core Java SimpleDateFormat class to do the conversion, using the formatter string shown in my code comments below. This all works fine.

My question is about thread safety. The SimpleDateFormat API docs state that it is not thread safe. For that reason I have created a separate instance of the date format object for each instance of my converter object. However, I'm not sure if this is enough. My DateFormat object is stored as a member of the DTGDateConverter.

QUESTION: Will two threads every simultaneously access the same instance of a Converter object in JSF?

If the answer is yes, then my Converter is probably at risk.

/**
 * <p>JSF Converter used to convert from java.util.Date to a string.
 * The SimpleDateFormat format used is: ddHHmm'Z'MMMyy.</p>
 * 
 * <p>Example: October 31st 2010 at 23:59 formats to 312359ZOCT10</p>
 * 
 * @author JTOUGH
 */
public class DTGDateConverter implements Converter {

    private static final Logger logger = 
        LoggerFactory.getLogger(DTGDateConverter.class);

    private static final String EMPTY_STRING = "";

    private static final DateFormat DTG_DATE_FORMAT = 
        MyFormatterUtilities.createDTGInstance();

    // The 'format' family of core Java classes are NOT thread-safe.
    // Each instance of this class needs its own DateFormat object or
    // runs the risk of two request threads accessing it at the same time.
    private final DateFormat df = (DateFormat)DTG_DATE_FORMAT.clone();

    @Override
    public Object getAsObject(
            FacesContext context, 
            UIComponent component, 
            String stringValue)
            throws ConverterException {
        Date date = null;
        // Prevent ParseException when an empty form field is submitted
        // for conversion
        if (stringValue == null || stringValue.equals(EMPTY_STRING)) {
            date = null;
        } else {
            try {
                date = df.parse(stringValue);
            } catch (ParseException e) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Unable to convert string to Date object", e);
                }
                date = null;
            }
        }
        return date;
    }

    @Override
    public String getAsString(
            FacesContext context, 
            UIComponent component, 
            Object objectValue)
            throws ConverterException {
        if (objectValue == null) {
            return null;
        } else if (!(objectValue instanceof Date)) {
            throw new IllegalArgumentException(
                "objectValue is not a Date object");
        } else {
            // Use 'toUpperCase()' to fix mixed case string returned
            // from 'MMM' portion of date format
            return df.format(objectValue).toUpperCase();
        }
    }

}
like image 347
Jim Tough Avatar asked Jan 21 '23 22:01

Jim Tough


1 Answers

Will two threads every simultaneously access the same instance of a Converter object in JSF?

Depends on how you use the converter. If you use

<h:inputWhatever>
    <f:converter converterId="converterId" />
</h:inputWhatever>

then a new instance will be created for every input element in view, which is threadsafe (expect of the very rare edge case that the enduser has two identical views in two browser tabs in the same session and simultaneously issues a postback on the both views).

If you however use

<h:inputWhatever converter="#{applicationBean.converter}" />

then the same instance will be shared across all views of the entire application, which is thus not threadsafe.

You're however cloning a static DataFormat instance everytime you create the converter. That part is already not threadsafe. You may risk that you're cloning an instance while its internal state is been changed because it's been used somewhere else. Also, cloning an existing instance isn't necessarily cheaper than creating a new instance.

I would recommend to just declare it threadlocal (i.e. inside the method block), regardless of how you use the converter. If the expensiveness of creating the DateFormat everytime is a major concern (did you profile it?), then consider replacing it by JodaTime.

like image 144
BalusC Avatar answered Jan 28 '23 23:01

BalusC