javax.validation.constraints.Pattern注释的参数化错误消息?

我有一个实体,其字段类型为String ,我在其上定义了@Pattern注释,强制匹配给定正则表达式的字段内容。 现在我想知道,是否可以参数化约束,例如在定义的validation错误消息中显示与正则表达式不匹配的第一个字符。

更糟糕的是,为注释违规显示的错误消息不是直接在注释中定义,而是在属性文件中定义,如下例所示:

示例类:

 public class Address { @Pattern(regexp="[a-zA-Z]*", message="paremeterizedMessage") private String street; } 

示例属性文件:

 parameterizedMessage = Invalid character {0}. Only characters az, AZ allowed. 

用javax.validation做这样的事情有可能吗? 我假设@Pattern注释无法参数化错误消息。 但也许可以使用参数化validation消息定义我自己的ConstraintValidator

考虑到某些validation注释(例如@Size(min=1,max=5)允许带有注释参数的参数化错误消息,例如The String must have a length of {min} to {max} characters. ,我找到了参数化错误消息的解决方案,通常使用占位符,例如{0}{1} ,…:

定义自己的validation约束,例如:

 @Constraint(validatedBy=OnlyCharactersAllowedValidator.class) @Documented @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface OnlyCharactersAllowed { String message() default "parameterizedMessage"; Class[] groups() default {}; Class[] payload() default {}; } 

在validation器类中,reflection可用于扩展存储所有注释参数的映射(例如@Size minmax ),并且可以为键0等添加其他参数:

 public class OnlyCharactersAllowedValidator implements ConstraintValidator { private static final String validCharacters = "abcdefghijklmnopqrstuvwxyz"; @Override public boolean isValid(String text, ConstraintValidatorContext constraintContext) { for (int index = 0; index < text.length; index++) { String aCharacter = text.substring(index, index+1); if (validCharacters.indexOf(aCharacter) < 0) { /* Within this message call the magic happens: {0} is mapped to the invalid character. */ addMessageParameter(constraintContext, aCharacter); /* Create violation message manually and suppress the default message. */ constraintContext.buildConstraintViolationWithTemplate(constraintContext.getDefaultConstraintMessageTemplate()).addConstraintViolation(); constraintContext.disableDefaultConstraintViolation(); /* No further validation: show only one error message for invalid characters. */ break; } } } private void addMessageParameter(ConstraintValidatorContext constraintContext, Object... parameter) { try { /* Get map for parameters (reflection necessary). */ Field descriptorField = ConstraintValidatorContextImpl.class.getDeclaredField("constraintDescriptor"); descriptorField.setAccessible(true); @SuppressWarnings("unchecked") ConstraintDescriptorImpl descriptor = (ConstraintDescriptorImpl) descriptorField.get(constraintContext); Map attributes = descriptor.getAttributes(); /* Copy immutable Map to new Map. */ Map newAttributes = new HashMap(attributes.size() + parameter.length); for (String key : attributes.keySet()) { newAttributes.put(key, attributes.get(key)); } /* Add given parameters to attributes. */ Integer parameterCounter = 0; for (Object param : parameter) { newAttributes.put(parameterCounter.toString(), param); parameterCounter++; } /* Set new Map in Descriptor (reflection necessary). */ Field attributesField = ConstraintDescriptorImpl.class.getDeclaredField("attributes"); attributesField.setAccessible(true); attributesField.set(descriptor, newAttributes); } catch (NoSuchFieldException | IllegalAccessException | SecurityException | ClassCastException e1) { /* Do nothing in case of exception. Unparameterized message is shown. */ } } } 

如果您的validation消息是在属性文件中定义的,则此解决方案甚至可以工作。

 parameterizedMessage = Invalid character: Do not use the {0} character.