Java 在bean验证消息中插入特定于验证的参数

Java 在bean验证消息中插入特定于验证的参数,java,jakarta-ee,bean-validation,Java,Jakarta Ee,Bean Validation,我有一个自定义bean验证器,它检查实体上的给定字段在某些情况下是否唯一。如果验证失败,则消息应包括已存在实体的字段(例如ID)。例如,信息应该是: "Product 42 already has such a value defined, choose a unique value." 这是否可以使用bean验证 在AFAICS中,消息格式可能包括参数,例如: "Length must be between {min} and {max}." 但这只能引用验证注释的“静态”属性,在这种情况

我有一个自定义bean验证器,它检查实体上的给定字段在某些情况下是否唯一。如果验证失败,则消息应包括已存在实体的字段(例如ID)。例如,信息应该是:

"Product 42 already has such a value defined, choose a unique value."
这是否可以使用bean验证

在AFAICS中,消息格式可能包括参数,例如:

"Length must be between {min} and {max}."
但这只能引用验证注释的“静态”属性,在这种情况下:

@Size(min=1, max=16)
private String name;

在我的情况下,该值仅在我的自定义验证器的
isValid
中已知。

你说得对!,为了你想要的!,您可以在isValid()方法内生成约束冲突消息。为此,约束注释应该特定于应用它的特定类,并且应该是类级别的验证约束。在isValid中,在验证失败时返回false之前,您可以创建包含类实例值的消息。例如:

@check class Test{ int id; @validations...on fields}.

public boolean isValid(Test value, ConstraintValidatorContext context) 
{
// your check logic
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("It should be different for(custom message) .."+ value.id).addConstraintViolation();
return false; // based on constraint filure.

}

但我认为您希望使用字段级注释来实现这一点!期待您的结果,我不知道这一点。

这并不是最好的解决方案,但我们最终在顶级异常处理代码中添加了如下内容:

String getConstraintViolationMessages(ConstraintViolationException e) {
    StringBuilder sb = new StringBuilder();
    for (ConstraintViolation<?> violation : e.getConstraintViolations()) {
        sb.append(getMessage(violation));
        sb.append("\n");
    }
    sb.setLength(sb.length() - 1);
    return sb.toString();
}

String getMessage(ConstraintViolation<?> violation) {
    String key = violation.getMessageTemplate();
    String messageFormat = localize(key);

    Object entity = violation.getRootBean();
    String identifier;
    if (entity instanceof PrimaryKeyed) {
        identifier = String.valueOf(((PrimaryKeyed) entity).getId());
    } else {
        identifier = entity.toString();
    }

    return MessageFormat.format(messageFormat, identifier);
}
String getConstraintViolationMessages(ConstraintViolationException e){
StringBuilder sb=新的StringBuilder();
for(ConstraintViolations冲突:e.getConstraintViolations()){
sb.append(getMessage(违规));
某人附加(“\n”);
}
sb.setLength(sb.length()-1);
使某人返回字符串();
}
字符串getMessage(约束冲突){
字符串键=冲突。getMessageTemplate();
字符串messageFormat=本地化(键);
对象实体=违例。getRootBean();
字符串标识符;
if(PrimaryKeyed的实体实例){
identifier=String.valueOf((PrimaryKeyed)entity.getId());
}否则{
标识符=entity.toString();
}
返回MessageFormat.format(MessageFormat,标识符);
}

请注意,
PrimaryKeyed
是在实体上使用的自定义接口。我们还有一些上面没有显示的其他接口和自定义处理。

问题是我不想在验证器中构造最终消息,只想构造一种格式(用于翻译)和参数。但我想我应该在验证器中本地化消息。我发布了我们最终得到的解决方案,作为另一个答案。但是我认为你的答案允许更具体的错误消息,即使本地化必须在验证器内部完成,我也接受了。这两个方法在哪个类中?使用
context.buildConstraintViolationWithTemplate(“{no.mobitroll.rest.resources.entities.beans.validators.QuizType.enum}”)的自定义约束。addConstraintViolation()还没有插值。@Stephane我们在顶级异常处理程序类中有它们,这可能是一件好事。在哪里添加这一点实际上取决于您的体系结构和您使用的框架,所以很遗憾,我不能给出更具体的答案。