【问题标题】:Issue with message expressions in hibernate validator休眠验证器中的消息表达式问题
【发布时间】:2013-11-27 17:07:06
【问题描述】:

我正在做一个项目,并且我已经使用 Hibernate Validator 有一段时间了。 最近我尝试在验证消息中使用Interpolation with message expressions(具有 EL 功能),但我得到的结果不一致(据我所知)。

根据有关消息插值步骤的文档,消息参数(包含在“{..}”中的参数)在评估消息表达式(包含在“${..}”中的参数)之前解析。因此,我的结论是允许写这样的消息:

    ${validatedValue > someValue ? '{x.y.z.message}' : '{x.y.w.message}'}

并期望其键为x.y.z.messagex.y.w.message 的消息文字是结果,其中x.y.z.messagex.y.w.message 被假定为有效且已在正确引导的资源中定义的消息键捆绑

为了澄清问题,我使用 TestNG 编写了一个测试用例,并针对 hibernate-validator-5.0.1.Finalhibernate-validator-5.1.0-Alpha 运行它。正如在测试 cmets 中指出的那样,这些版本获得的结果在这个特定问题上会有所不同,这暗示了我对实现错误的看法。我最初认为这可能与[HV-798] 有关,但似乎更深层次。

这是测试用例:

import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.constraints.Size;

import org.testng.annotations.Test;

import static org.testng.Assert.assertEquals;

public class HibernateValidationTest
{
    public class Entity
    {
        public int  caseIndex;

        @Size(min = 4, max = 10, message = "${validatedValue.length() < min ? 'Error msg.#1' : 'Error msg.#2'}")
        public String getMessage1()
        {
            if (caseIndex == 0)
                return "abc";
            return "abcd";
        }

        @Size(min = 4, max = 10, message = "{javax.validation.constraints.Size.message}")
        public String getMessage2()
        {
            if (caseIndex == 1)
                return "abc";
            return "abcd";
        }

        @Size(min = 4, max = 10, message = "{javax.validation.constraints.Size.message} (${validatedValue.length() < min ? 'Error msg.#3' : '{javax.validation.constraints.Size.message}'})")
        public String getMessage3()
        {
            if (caseIndex == 2)
                return "abc";
            return "abcd";
        }
    }

    @Test
    public void testValidatorBug()
    {
        Validator validator = javax.validation.Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<Entity>> violations;
        ConstraintViolation<Entity> violation;
        Entity entity = new Entity();

        /**
         * PASS
         */
        entity.caseIndex = 0;
        violations = validator.validate(entity);
        assertEquals(violations.size(), 1);
        violation = violations.iterator().next();
        assertEquals(violation.getMessage(), "Error msg.#1");

        /**
         * PASS
         */
        entity.caseIndex = 1;
        violations = validator.validate(entity);
        assertEquals(violations.size(), 1);
        violation = violations.iterator().next();
        assertEquals(violation.getMessage(), "size must be between 4 and 10");

        /**
         * FAIL
         * 
         * Violation message:
         * 
         * - on version hibernate-validator-5.0.1.Final: 
         *  size must be between 4 and 10 (${validatedValue.length() < min ? 'Error msg.#3' : '{javax.validation.constraints.Size.message}'})
         * 
         * - on hibernate-validator-5.1.0-20131114.015215-37: 
         *  {javax.validation.constraints.Size.message} (${validatedValue.length() < min ? 'Error msg.#3' : '{javax.validation.constraints.Size.message}'})
         */
        entity.caseIndex = 2;
        violations = validator.validate(entity);
        assertEquals(violations.size(), 1);
        violation = violations.iterator().next();
        assertEquals(violation.getMessage(), "size must be between 4 and 10 (Error msg.#3)");
    }
}

在此测试中,Entity.getMessage3() 演示了测试最后一部分发现的问题。根据我的理解,这条消息一定是size must be between 4 and 10 (Error msg.#3),但在5.0.1版本上是size must be between 4 and 10 (${validatedValue.length() &lt; min ? 'Error msg.#3' : '{javax.validation.constraints.Size.message}'}),并且 5.1.0.Alpha 上的{javax.validation.constraints.Size.message} (${validatedValue.length() &lt; min ? 'Error msg.#3' : '{javax.validation.constraints.Size.message}'})

任何人都可以对此进行评估并提出问题或帮助我找出自己的错误。

感谢您的宝贵时间。

【问题讨论】:

    标签: java expression message bean-validation hibernate-validator


    【解决方案1】:

    这似乎与 EL 表达式中消息参数的嵌套有关。

    阅读规范的措辞,我看不出为什么不允许这样做,但我不确定我们是否有意支持这种情况(我想我们会在这种情况下提供一个例子)。 I have forwarded这个问题,看看 BV EG 上其他人的想法。

    Hibernate Validator 当前检测到这种嵌套并在这种情况下引发异常。这就是插值消息保持不变的原因(这是规范要求的)。

    【讨论】:

    • 谢谢,我会等待一些提示。同时我花时间在休眠源中跟踪这个,发现私有 RegEx 模式常量 ResourceBundleMessageInterpolator.MESSAGE_PARAMETER_PATTERN 是导致问题的原因在ResourceBundleMessageInterpolator.interpolateMessage(String message, Context context, Locale locale) 中使用。模式"((\\\\*)\\{[^\\}]+?\\})" 显然忽略了花括号对的嵌套,并在第一次出现右花括号时终止,这是问题的根源。
    • 我通过将模式更改为MESSAGE_PARAMETER_PATTERN = Pattern.compile( "((\\\\*)\\{[^\\}\\{]+?\\})" )MESSAGE_EXPRESSION_PATTERN = Pattern.compile( "((\\\\*)\\$?\\{[^\\}\\{]+?\\})" ) 来修复它。应用这个并重建 HV 通过了我所有的测试。如果您可以评估并断言这是解决该问题的方法,那就太好了。
    • 我们必须首先根据规范得出结论,是否支持这种嵌套形式。您可能想跟踪BVAL-469。目前,如果您找到适合您的解决方案,我建议您将调整后的 ResourceBundleMessageInterpolator 移动到您自己的代码库中,并配置验证引擎以使用此自定义插值器,在 META-INF/validation.xml 中或在引导验证器时通过 API。
    【解决方案2】:

    在翻转这个之后,我决定遵循@Gunnar 的建议,因为我们使用的是 OSGi,所以我设法做了一个快速的 Bundle Class Path 技巧,将修改后的 ResourceBundleMessageInterpolator 放在原来的位置之前由 HV 自动拾取。

    【讨论】:

      猜你喜欢
      • 2017-09-06
      • 1970-01-01
      • 2011-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-26
      相关资源
      最近更新 更多