如何在自定义注释的默认消息中获取字段名称?

时间:2020-08-26 20:23:15

标签: java rest validation jackson annotations

我已经创建了自定义注释,以检查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} 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;
        }

    }
}

但是,如果我在属性上使用了此注释。 例如:

@CheckNotNull(value = "UserName")
private String login

我有另一个类,其中捕获了ConstraintViloationException。使用@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("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();   
    }
}

我的逻辑不适用于应用自定义注释。我的自定义注释有任何问题吗?

欢迎任何输入。谢谢。

2 个答案:

答案 0 :(得分:1)

您需要使用您已声明为任何动态消息的任何字段传递该属性 {value} ;

在您的情况下,您需要将其作为 @CheckNotNull(value =“ name”)传递。

@CheckNotNull(value="name")
private String firstName;

@CheckNotNull(value="UserName")
private String name;

这将为您提供帮助。

答案 1 :(得分:0)

我已覆盖ValidationMessages.properties文件。

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

然后,在我的回复课中

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();   
    }

我已经为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;
    }

因此,如果它们不是@ NotNull,@ NotEmpty和@NotBlank批注的自定义消息,则将默认消息中的占位符替换为从路径中提取的字段名称,以便获得用户友好的错误消息。 例子:

@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"
相关问题