使用 Formatter 时如何防止 Spring 使用默认转换逻辑

Joh*_*n S 5 data-binding spring spring-mvc

我编写了一个自定义 Spring 格式化程序(它实现了org.springframework.format.Formatter接口),用于将表单输入值转换BigDecimal为美元输入值。格式化程序不接受小数点后超过两位数的值。在这种情况下, aParseException由格式化程序的parse()方法抛出。

public class InputDollarBigDecimalFormatter
    implements Formatter<BigDecimal>
{
    @Override
    public BigDecimal parse(String text, Locale locale)
        throws ParseException
    {
        // ...
    }

    @Override
    public String print(BigDecimal amount, Locale locale)
    {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

格式化程序已注册,因此可以使用名为@InputDollarBigDecimalFormat.

我的表单支持对象中应用了格式化程序的字段如下所示:

@InputDollarBigDecimalFormat
private BigDecimal price;
Run Code Online (Sandbox Code Playgroud)

格式化程序工作正常。

问题是当ParseException抛出 时,Spring 仍然尝试BigDecimal使用默认转换将输入值转换为 a 。该装置的输入值100.123仍成功地转换为一个BigDecimal,即使我的自定义格式抛出一个ParseException

BigDecimal当我的自定义格式化程序通过抛出 a 拒绝该值时,如何防止 Spring 将输入值转换为a ParseException

我正在使用 Spring 3.1.0。

Spring 格式化程序在此处记录


更新:

使用调试器单步执行代码后,我看到这个逻辑在org.springframework.beans.TypeConverterDelegate类中。Spring 显然是故意这样做的,所以我只能看到以下可能的解决方案:

(1)如果可能的话,未注册的默认PropertyEditorBigDecimal值。看来 Spring 注册了 aorg.springframework.beans.propertyeditors.CustomNumberEditor用于将字符串转换为BigDecimal. 当然,此解决方案的缺点是默认值PropertyEditor不适用于其他BigDecimal字段(不使用自定义格式化程序)。

(2) 创建一个Dollar包装 a的类BigDecimal并更改自定义格式化程序以使用Dollar该类。字段类型也必须更改为Dollar。在处理这些值时,这会有点麻烦。

(3) 也许 Spring 已经意识到PropertyEditor当自定义格式化程序拒绝一个值时回退到默认值是不正确的,因此这已在更新的 Spring 版本中更改。我很怀疑,但如果有人知道任何一种方式,您的帮助将不胜感激。

(4) 但也许正确的解决方案是将自定义格式化程序视为PropertyEditor通过允许更多格式来帮助默认设置。除了将值限制为两位小数之外,我的自定义格式化程序还允许输入值包含美元符号和逗号。我可以离开那个逻辑,但删除小数位限制。然后我可以添加一个自定义 bean 验证 (JSR 303) 约束,如果该值在小数位后没有正好两位数(除非它没有),则拒绝该值。我只需要用约束来注​​释我的字段:

@InputDollarBigDecimalFormat
@WholeDollarOrCentsConstraint
private BigDecimal price;
Run Code Online (Sandbox Code Playgroud)

当然,除了格式化程序的错误消息之外,我还必须为约束添加错误消息。

如果其中任何一个对您来说似乎是正确的解决方案,请随意添加您的推理答案。

小智 0

这对我有用。如果您查看TypeConverterDelegate,它所做的第一件事(以及后来作为“后备转换”位的一部分)是检查是否有为给定类型注册的自定义 PropertyEditor。如果有,它完全绕过该conversionService部分(这就是吞噬您的异常的部分)并使用编辑器

因此,您可以尝试创建自己的类来扩展 PropertyEditorSupport并注册它,而不是您的建议(1) BigDecimal(有关如何执行此操作的示例,请参阅此处)。IllegalArgumentException然后你可以在你的方法中添加一个setAsText