考虑到一些验证注解(例如@Size(min=1,max=5))允许参数化错误消息及其注解参数(例如The String must have a length of {min} to {max} characters.),我找到了一个通常使用占位符(例如{0}、@)的参数化错误消息的解决方案987654324@, ...:
定义自己的验证约束,例如:
@Constraint(validatedBy=OnlyCharactersAllowedValidator.class)
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface OnlyCharactersAllowed {
String message() default "parameterizedMessage";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
在验证器类中,反射可用于扩展存储所有注释参数的映射(例如min 和max 用于@Size)并且可以为键0 添加其他参数, 1等:
public class OnlyCharactersAllowedValidator implements ConstraintValidator<OnlyCharactersAllowed,String>
{
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<OnlyCharactersAllowed> descriptor = (ConstraintDescriptorImpl<OnlyCharactersAllowed>) descriptorField.get(constraintContext);
Map<String,Object> attributes = descriptor.getAttributes();
/* Copy immutable Map to new Map. */
Map<String,Object> newAttributes = new HashMap<String,Object>(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. */
}
}
}
即使您的验证消息是在诸如属性文件中定义的,此解决方案也可以工作。
parameterizedMessage = Invalid character: Do not use the {0} character.