英文:
How to get field Name in default message in custom annotation?
问题
我已创建自定义注解,用于在我的REST API项目的模型类属性中检查非空值。
@Documented
@Target({ ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@ReportAsSingleViolation
@Constraint(validatedBy = CheckNotNull.NotNullValidator.class)
public @interface CheckNotNull {
    String value() default "";
    String message() default "{value} 不能为空";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    class NotNullValidator implements ConstraintValidator<CheckNotNull, String> {
        @Override
        public void initialize(CheckNotNull constraintAnnotation) {
        }
        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
            return "null".equalsIgnoreCase(value) || value == null || value.trim().isEmpty();
        }
    }
}
然而,如果我在属性上使用此注解。
@CheckNotNull(value = "UserName")
private String login;
我有另一个类捕获了 ConstraintViolationException。使用 @NotNull 注解时,它能够正常工作。
public final class ValidationExceptionMapper implements ExceptionMapper<ValidationException> {
    @Override
    public Response toResponse(final ValidationException exception) {
        RestError error = new RestError();
        if (exception instanceof ConstraintViolationException) {
            error.setHttpStatusCode(Response.Status.BAD_REQUEST.getStatusCode());
            error.setCode(ErrorCodes.ERR_INVALID_INPUT);
            final ConstraintViolationException cve = (ConstraintViolationException) exception;
            StringBuilder msgBuilder = new StringBuilder("检测到以下约束违规:");
            for(ConstraintViolation<?> violation: cve.getConstraintViolations()) {
                msgBuilder.append(StringEscapeUtils.escapeHtml(violation.getMessage()));
            }
            error.setMessage(msgBuilder.toString());
        }
        return Response.status(error.getHttpStatusCode())
                .entity(error)
                .type(MediaType.APPLICATION_JSON)
                .build();   
    }
}
但使用自定义注解时,我的逻辑无法正常工作。我的自定义注解是否存在问题?
欢迎提供任何意见。谢谢。
英文:
I have created custom annotation to check not null value for my model class attribute in my REST API project.
@Documented
@Target({ ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@ReportAsSingleViolation
@Constraint(validatedBy = CheckNotNull.NotNullValidator.class)
public @interface CheckNotNull {
    String value() default "";
    String message() default "{value} can not be null or empty ";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    class NotNullValidator implements ConstraintValidator<CheckNotNull, String> {
        @Override
        public void initialize(CheckNotNull constraintAnnotation) {
        }
        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
            return "null".equalsIgnoreCase(value) ? true : value == null ? true : value.trim().equals("") ? true :false;
        }
    }
}
However, if I used this annotation on attribute.
ex:
@CheckNotNull(value = "UserName")
private String login
I have another class where ConstraintViloationException is captured. With @NotNull annotation it is perfectly working.
public final class ValidationExceptionMapper implements ExceptionMapper<ValidationException> {
    @Override
    public Response toResponse(final ValidationException exception) {
        RestError error = new RestError();
        
        if (exception instanceof ConstraintViolationException) {
            error.setHttpStatusCode(Response.Status.BAD_REQUEST.getStatusCode());
            error.setCode(ErrorCodes.ERR_INVALID_INPUT);
            final ConstraintViolationException cve = (ConstraintViolationException) exception;
            
            StringBuilder msgBuilder = new StringBuilder("Following constraint violations have been detected: ");
            for(ConstraintViolation<?> violation: cve.getConstraintViolations()) {
                    msgBuilder.append(StringEscapeUtils.escapeHtml(violation.getMessage()));
            }
            error.setMessage(msgBuilder.toString());
        }
        return Response.status(error.getHttpStatusCode())
                .entity(error)
                .type(MediaType.APPLICATION_JSON)
                .build();   
    }
}
My logic is not working with applying custom annotation. Any issue with my custom annotation?
Any inputs are most welcome. Thank you.
答案1
得分: 1
你需要将该属性与您声明为任何动态消息的字段一起传递 {value} ;
在您的情况下,您需要将其传递如下: @CheckNotNull(value="name")。
@CheckNotNull(value="name")
private String firstName;
@CheckNotNull(value="UserName")
private String name;
这将对您有所帮助。
英文:
You need to pass that attribute with field whatever you had declared as any dynamic message {value} ;
In your case you need pass that as @CheckNotNull(value="name").
@CheckNotNull(value="name")
private String firstName;
@CheckNotNull(value="UserName")
private String name;
This will help you.
答案2
得分: 0
我已经覆盖了ValidationMessages.properties文件。
javax.validation.constraints.NotNull.message = {0} 不能为空。
org.hibernate.validator.constraints.NotBlank.message = {0} 不能为空
org.hibernate.validator.constraints.NotEmpty.message = {0} 不能为空
然后,在我的响应类中:
public Response toResponse(final ValidationException exception) {
    RestError error = new RestError();
    StringBuilder errorPath = new StringBuilder();
    if (exception instanceof ConstraintViolationException) {
        error.setHttpStatusCode(Response.Status.BAD_REQUEST.getStatusCode());
        final ConstraintViolationException cve = (ConstraintViolationException) exception;
        StringBuilder msgBuilder = new StringBuilder("以下约束违规已被检测到: ");
        for (ConstraintViolation<?> violation : cve.getConstraintViolations()) {
            Class<?> annotationType = violation.getConstraintDescriptor().getAnnotation().annotationType();
            if (annotationType == NotEmpty.class || annotationType == NotNull.class
                    || annotationType == NotBlank.class) {
                msgBuilder = getErrorMessage(violation, msgBuilder);
            } else {
                msgBuilder.append(StringEscapeUtils.escapeHtml(violation.getMessage()));
            }
            errorPath.append(" 路径: ").append(violation.getPropertyPath().toString());
        }
        error.setMessage(msgBuilder.toString());
    }
    return Response.status(error.getHttpStatusCode())
            .entity(error)
            .type(MediaType.APPLICATION_JSON)
            .build();
}
我还为getErrorMessage编写了单独的方法:
private StringBuilder getErrorMessage(ConstraintViolation<?> violation, StringBuilder msgBuilder) {
    // 对于默认错误消息
    if (violation.getMessage().contains("{0}")) {
        String[] splitPath = violation.getPropertyPath().toString().split("[.]");
        String fieldName = splitPath[splitPath.length - 1];
        String messageWithFieldName = MessageFormat.format(violation.getMessage(), fieldName);
        msgBuilder.append((messageWithFieldName)).append(";");
    } else {
        // 对于自定义错误消息
        msgBuilder.append(violation.getMessage()).append(";");
    }
    return msgBuilder;
}
因此,如果@NotNull、@NotEmpty和@NotBlank注解没有自定义消息,那么将默认消息中的占位符替换为从路径中提取的字段名,以便获得用户友好的错误消息。
示例:
@NotNull
private String name;
消息: "以下约束违规已被检测到: name 不能为空"
@NotNull(message = "用户名不能为空")
private String name;
消息: "以下约束违规已被检测到: 用户名不能为空"
@NotNull
@JsonProperty("username")
private String name;
消息: "以下约束违规已被检测到: name 不能为空"
英文:
I have overridden ValidationMessages.properties file.
javax.validation.constraints.NotNull.message  = {0} cannot be null or empty.
org.hibernate.validator.constraints.NotBlank.message  = {0} cannot be null or empty
org.hibernate.validator.constraints.NotEmpty.message  = {0} cannot be null or empty
And then, In my response class
public Response toResponse(final ValidationException exception) {
        RestError error = new RestError();
        StringBuilder errorPath = new StringBuilder();
        if (exception instanceof ConstraintViolationException) {
            error.setHttpStatusCode(Response.Status.BAD_REQUEST.getStatusCode());
            final ConstraintViolationException cve = (ConstraintViolationException) exception;
            
            StringBuilder msgBuilder = new StringBuilder("Following constraint violations have been detected: ");
            for(ConstraintViolation<?> violation: cve.getConstraintViolations()) {
                Class<?> annotationType = violation.getConstraintDescriptor().getAnnotation().annotationType();
               if (annotationType == NotEmpty.class || annotationType == NotNull.class
                        || annotationType == NotBlank.class) {
                    msgBuilder = getErrorMessage(violation, msgBuilder);
                }
                else {
                    msgBuilder.append(StringEscapeUtils.escapeHtml(violation.getMessage()));
                }
                errorPath.append(" path: ").append(violation.getPropertyPath().toString());
                
               
            }
            error.setMessage(msgBuilder.toString());
        } 
        return Response.status(error.getHttpStatusCode())
                .entity(error)
                .type(MediaType.APPLICATION_JSON)
                .build();   
    }
And I have written separate method for getErrorMessage
private StringBuilder getErrorMessage(ConstraintViolation<?> violation, StringBuilder msgBuilder) {
        // For default error message
        if (violation.getMessage().contains("{0}")) {
            String[] splitPath =  violation.getPropertyPath().toString().split("[.]");
            String fieldName = splitPath[splitPath.length - 1];
            String messageWithFieldName = MessageFormat.format(violation.getMessage(), fieldName);
            msgBuilder.append((messageWithFieldName)).append(";");
        } else {
            // For customized error message
            msgBuilder.append(violation.getMessage()).append(";");
        }
        return msgBuilder;
    }
so if their is no custom message for @NotNull, @NotEmpty and @NotBlank annotation, then replace placeholder in default message with field name which is extracted from the path in order to have user-friendly error message.
examples:
@NotNull
private String name;
message: "Following constraint violations have been detected: name cannot be null or empty"
@NotNull(message = "UserName can not be null")
private String name;
message: "Following constraint violations have been detected: UserName can not be null"
@NotNull
@JsonProperty("username")
private String name;
message: "Following constraint violations have been detected: name cannot be null or empty"
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论