JSF 自定义日期转换器 - 线程安全吗?

发布于 2024-10-07 02:01:26 字数 2714 浏览 5 评论 0原文

我在 JSF 1.2 中创建了一个自定义 Converter 来转换 Date 对象。日期具有非常特殊的格式。我已经使用核心 Java SimpleDateFormat 类实现了我的转换器来进行转换,并使用下面代码注释中显示的格式化程序字符串。这一切都很好。

我的问题是关于线程安全的。 SimpleDateFormat API 文档声明它不是线程安全的。因此,我为转换器对象的每个实例创建了一个单独的日期格式对象实例。但是,我不确定这是否足够。我的 DateFormat 对象存储为 DTGDateConverter 的成员。

问题:两个线程是否会同时访问 JSF 中 Converter 对象的同一个实例?

如果答案是肯定的,那么我的 Converter 可能面临风险。

/**
 * <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();
        }
    }

}

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();
        }
    }

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

祁梦 2024-10-14 02:01:26

两个线程会同时访问 JSF 中 Converter 对象的同一个实例吗?

取决于您如何使用转换器。如果您使用

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

,那么将为视图中的每个输入元素创建一个新实例,这是线程安全的(除了非常罕见的边缘情况外,最终用户在同一会话的两个浏览器选项卡中拥有两个相同的视图,并同时在两种观点)。

但是,如果您使用

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

,则同一实例将在整个应用程序的所有视图之间共享,因此不是线程安全的。

然而,每次创建转换器时,您都会克隆一个静态 DataFormat 实例。该部分已经不是线程安全的。您可能会面临克隆实例的风险,而其内部状态会因为已在其他地方使用而发生更改。此外,克隆现有实例并不一定比创建新实例便宜。

我建议将其声明为线程本地(即在方法块内),无论您如何使用转换器。如果每次创建 DateFormat 的成本是一个主要问题(您是否分析过它?),那么请考虑将其替换为 JodaTime

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.

决绝 2024-10-14 02:01:26

日期格式不同步。它
建议单独创建
为每个线程格式化实例。如果
多个线程访问一种格式
同时,必须同步
外部。

是的,这里不是线程安全的。

将其放在方法本地并为每个线程创建实例

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.

Yes it is not thread safe here.

Put it local to method and create instance per thread

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文