【问题标题】:How do I dynamically resolve message parameters with Hibernate Validator?如何使用 Hibernate Validator 动态解析消息参数?
【发布时间】:2011-06-13 12:02:36
【问题描述】:

我正在使用 Hibernate Validator,并希望在错误消息中解析类别名称。考虑这个简单的场景:

public class Category {
    private String name;
}

public class Product {
    @HazardousCategoryConstraint(message = "{haz.cat.error}")
    private Category category;
    private String name;
}

public class InventoryReport {
    @Valid
    private List<Product> products;
}


ValidationMessages.properties
haz.cat.error={name} is a product in the hazardous category list.

假设我有一个有效的 HazardousCategoryConstraint 实现。验证器根据限制名称列表检查每个类别的名称。当我调用 validate(InventoryReport) 时,我得到了我期望的错误数,除了它们是相同的字符串。我希望看到类别名称解析到每条消息中。有人可以给我举一个如何动态解析参数的例子,或者告诉我怎么做吗?

【问题讨论】:

  • 您要求的是:如何在错误消息字符串中输入值? ——这对吗?
  • @Ralph - 没错,但更具体地说,我希望它是动态的。我有许多具有唯一名称的类别实例。
  • 但是你想在消息中输入的名字是你的验证者知道的,对吧?

标签: java hibernate spring validation hibernate-validator


【解决方案1】:

IMO,简单的解决方案是创建javax.validation.MessageInterpolator 的自定义实现。将主要工作委托给 Hibernate Validator 的 ResourceBundleMessageInterpolator,并在 CustomMessageInterpolator 中完成所需的替换工作。

public class CustomMessageInterpolator extends org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator {

    private static final Pattern MESSAGE_PARAMETER_PATTERN = Pattern.compile( "(\\{[^\\}]+?\\})" );

    @Override
    public String interpolate(String message, Context context) {
        String resolvedMessage = super.interpolate(message, context);
        resolvedMessage = replacePropertyNameWithPropertyValues(resolvedMessage, context.getValidatedValue());
        return resolvedMessage;
    }

    private String replacePropertyNameWithPropertyValues(String resolvedMessage, Object validatedValue) {
        Matcher matcher = MESSAGE_PARAMETER_PATTERN.matcher( resolvedMessage );
        StringBuffer sb = new StringBuffer();

        while ( matcher.find() ) {
            String parameter = matcher.group( 1 );

            String propertyName = parameter.replace("{", "");
            propertyName = propertyName.replace("}", "");

            PropertyDescriptor desc = null;
            try {
                desc = new PropertyDescriptor(propertyName, validatedValue.getClass());
            } catch (IntrospectionException ignore) {
                matcher.appendReplacement( sb, parameter );
                continue;
            }

            try {
                Object propertyValue = desc.getReadMethod().invoke(validatedValue);
                matcher.appendReplacement( sb, propertyValue.toString() );
            } catch (Exception ignore) {
                matcher.appendReplacement( sb, parameter );
            }
        }
        matcher.appendTail( sb );
        return sb.toString();
    }

}

@Test

public void validate() {
        Configuration<?> configuration = Validation.byDefaultProvider().configure();
        ValidatorFactory validatorFactory = configuration.messageInterpolator(new CustomMessageInterpolator()).buildValidatorFactory();
        Validator validator = validatorFactory.getValidator();

        Product p = new Product();
        Category cat = new Category();
        cat.setName("s"); //assume specified name is invalid
        p.setCategory(cat);

        Set<ConstraintViolation<Product>> violations = validator.validate(p);
        for(ConstraintViolation<Product> violation : violations) {
            System.out.println(violation.getMessage());
        }
    }

输出

s is a product in the hazardous category list.

【讨论】:

  • 如何设置自定义消息插值器以供恒定 JPA 使用?
  • 只是一个面向对象的东西:与其扩展 Hibernate Validator 的 ResourceBundleMessageInterpolator,我宁愿在 CustomMessageInterpolator 中使用一个委托来独立于 Hibernate 内部。
  • 这是我发布问题的同一问题的解决方案吗? stackoverflow.com/questions/58257635/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-10
  • 1970-01-01
  • 2014-03-05
  • 1970-01-01
  • 2011-12-31
  • 1970-01-01
相关资源
最近更新 更多