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

huangapple go评论107阅读模式
英文:

How to get field Name in default message in custom annotation?

问题

我已创建自定义注解,用于在我的REST API项目的模型类属性中检查非空值。

  1. @Documented
  2. @Target({ ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
  3. @Retention(RetentionPolicy.RUNTIME)
  4. @ReportAsSingleViolation
  5. @Constraint(validatedBy = CheckNotNull.NotNullValidator.class)
  6. public @interface CheckNotNull {
  7. String value() default "";
  8. String message() default "{value} 不能为空";
  9. Class<?>[] groups() default {};
  10. Class<? extends Payload>[] payload() default {};
  11. class NotNullValidator implements ConstraintValidator<CheckNotNull, String> {
  12. @Override
  13. public void initialize(CheckNotNull constraintAnnotation) {
  14. }
  15. @Override
  16. public boolean isValid(String value, ConstraintValidatorContext context) {
  17. return "null".equalsIgnoreCase(value) || value == null || value.trim().isEmpty();
  18. }
  19. }
  20. }

然而,如果我在属性上使用此注解。

  1. @CheckNotNull(value = "UserName")
  2. private String login;

我有另一个类捕获了 ConstraintViolationException。使用 @NotNull 注解时,它能够正常工作。

  1. public final class ValidationExceptionMapper implements ExceptionMapper<ValidationException> {
  2. @Override
  3. public Response toResponse(final ValidationException exception) {
  4. RestError error = new RestError();
  5. if (exception instanceof ConstraintViolationException) {
  6. error.setHttpStatusCode(Response.Status.BAD_REQUEST.getStatusCode());
  7. error.setCode(ErrorCodes.ERR_INVALID_INPUT);
  8. final ConstraintViolationException cve = (ConstraintViolationException) exception;
  9. StringBuilder msgBuilder = new StringBuilder("检测到以下约束违规:");
  10. for(ConstraintViolation<?> violation: cve.getConstraintViolations()) {
  11. msgBuilder.append(StringEscapeUtils.escapeHtml(violation.getMessage()));
  12. }
  13. error.setMessage(msgBuilder.toString());
  14. }
  15. return Response.status(error.getHttpStatusCode())
  16. .entity(error)
  17. .type(MediaType.APPLICATION_JSON)
  18. .build();
  19. }
  20. }

但使用自定义注解时,我的逻辑无法正常工作。我的自定义注解是否存在问题?

欢迎提供任何意见。谢谢。

英文:

I have created custom annotation to check not null value for my model class attribute in my REST API project.

  1. @Documented
  2. @Target({ ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
  3. @Retention(RetentionPolicy.RUNTIME)
  4. @ReportAsSingleViolation
  5. @Constraint(validatedBy = CheckNotNull.NotNullValidator.class)
  6. public @interface CheckNotNull {
  7. String value() default &quot;&quot;;
  8. String message() default &quot;{value} can not be null or empty &quot;;
  9. Class&lt;?&gt;[] groups() default {};
  10. Class&lt;? extends Payload&gt;[] payload() default {};
  11. class NotNullValidator implements ConstraintValidator&lt;CheckNotNull, String&gt; {
  12. @Override
  13. public void initialize(CheckNotNull constraintAnnotation) {
  14. }
  15. @Override
  16. public boolean isValid(String value, ConstraintValidatorContext context) {
  17. return &quot;null&quot;.equalsIgnoreCase(value) ? true : value == null ? true : value.trim().equals(&quot;&quot;) ? true :false;
  18. }
  19. }
  20. }

However, if I used this annotation on attribute.
ex:

  1. @CheckNotNull(value = &quot;UserName&quot;)
  2. private String login

I have another class where ConstraintViloationException is captured. With @NotNull annotation it is perfectly working.

  1. public final class ValidationExceptionMapper implements ExceptionMapper&lt;ValidationException&gt; {
  2. @Override
  3. public Response toResponse(final ValidationException exception) {
  4. RestError error = new RestError();
  5. if (exception instanceof ConstraintViolationException) {
  6. error.setHttpStatusCode(Response.Status.BAD_REQUEST.getStatusCode());
  7. error.setCode(ErrorCodes.ERR_INVALID_INPUT);
  8. final ConstraintViolationException cve = (ConstraintViolationException) exception;
  9. StringBuilder msgBuilder = new StringBuilder(&quot;Following constraint violations have been detected: &quot;);
  10. for(ConstraintViolation&lt;?&gt; violation: cve.getConstraintViolations()) {
  11. msgBuilder.append(StringEscapeUtils.escapeHtml(violation.getMessage()));
  12. }
  13. error.setMessage(msgBuilder.toString());
  14. }
  15. return Response.status(error.getHttpStatusCode())
  16. .entity(error)
  17. .type(MediaType.APPLICATION_JSON)
  18. .build();
  19. }
  20. }

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")

  1. @CheckNotNull(value="name")
  2. private String firstName;
  3. @CheckNotNull(value="UserName")
  4. 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").

  1. @CheckNotNull(value=&quot;name&quot;)
  2. private String firstName;
  3. @CheckNotNull(value=&quot;UserName&quot;)
  4. private String name;

This will help you.

答案2

得分: 0

我已经覆盖了ValidationMessages.properties文件。

  1. javax.validation.constraints.NotNull.message = {0} 不能为空。
  2. org.hibernate.validator.constraints.NotBlank.message = {0} 不能为空
  3. org.hibernate.validator.constraints.NotEmpty.message = {0} 不能为空

然后,在我的响应类中:

  1. public Response toResponse(final ValidationException exception) {
  2. RestError error = new RestError();
  3. StringBuilder errorPath = new StringBuilder();
  4. if (exception instanceof ConstraintViolationException) {
  5. error.setHttpStatusCode(Response.Status.BAD_REQUEST.getStatusCode());
  6. final ConstraintViolationException cve = (ConstraintViolationException) exception;
  7. StringBuilder msgBuilder = new StringBuilder("以下约束违规已被检测到: ");
  8. for (ConstraintViolation<?> violation : cve.getConstraintViolations()) {
  9. Class<?> annotationType = violation.getConstraintDescriptor().getAnnotation().annotationType();
  10. if (annotationType == NotEmpty.class || annotationType == NotNull.class
  11. || annotationType == NotBlank.class) {
  12. msgBuilder = getErrorMessage(violation, msgBuilder);
  13. } else {
  14. msgBuilder.append(StringEscapeUtils.escapeHtml(violation.getMessage()));
  15. }
  16. errorPath.append(" 路径: ").append(violation.getPropertyPath().toString());
  17. }
  18. error.setMessage(msgBuilder.toString());
  19. }
  20. return Response.status(error.getHttpStatusCode())
  21. .entity(error)
  22. .type(MediaType.APPLICATION_JSON)
  23. .build();
  24. }

我还为getErrorMessage编写了单独的方法:

  1. private StringBuilder getErrorMessage(ConstraintViolation<?> violation, StringBuilder msgBuilder) {
  2. // 对于默认错误消息
  3. if (violation.getMessage().contains("{0}")) {
  4. String[] splitPath = violation.getPropertyPath().toString().split("[.]");
  5. String fieldName = splitPath[splitPath.length - 1];
  6. String messageWithFieldName = MessageFormat.format(violation.getMessage(), fieldName);
  7. msgBuilder.append((messageWithFieldName)).append(";");
  8. } else {
  9. // 对于自定义错误消息
  10. msgBuilder.append(violation.getMessage()).append(";");
  11. }
  12. return msgBuilder;
  13. }

因此,如果@NotNull@NotEmpty@NotBlank注解没有自定义消息,那么将默认消息中的占位符替换为从路径中提取的字段名,以便获得用户友好的错误消息。

示例:

  1. @NotNull
  2. private String name;
  3. 消息: "以下约束违规已被检测到: name 不能为空"
  4. @NotNull(message = "用户名不能为空")
  5. private String name;
  6. 消息: "以下约束违规已被检测到: 用户名不能为空"
  7. @NotNull
  8. @JsonProperty("username")
  9. private String name;
  10. 消息: "以下约束违规已被检测到: name 不能为空"
英文:

I have overridden ValidationMessages.properties file.

  1. javax.validation.constraints.NotNull.message = {0} cannot be null or empty.
  2. org.hibernate.validator.constraints.NotBlank.message = {0} cannot be null or empty
  3. org.hibernate.validator.constraints.NotEmpty.message = {0} cannot be null or empty

And then, In my response class

  1. public Response toResponse(final ValidationException exception) {
  2. RestError error = new RestError();
  3. StringBuilder errorPath = new StringBuilder();
  4. if (exception instanceof ConstraintViolationException) {
  5. error.setHttpStatusCode(Response.Status.BAD_REQUEST.getStatusCode());
  6. final ConstraintViolationException cve = (ConstraintViolationException) exception;
  7. StringBuilder msgBuilder = new StringBuilder(&quot;Following constraint violations have been detected: &quot;);
  8. for(ConstraintViolation&lt;?&gt; violation: cve.getConstraintViolations()) {
  9. Class&lt;?&gt; annotationType = violation.getConstraintDescriptor().getAnnotation().annotationType();
  10. if (annotationType == NotEmpty.class || annotationType == NotNull.class
  11. || annotationType == NotBlank.class) {
  12. msgBuilder = getErrorMessage(violation, msgBuilder);
  13. }
  14. else {
  15. msgBuilder.append(StringEscapeUtils.escapeHtml(violation.getMessage()));
  16. }
  17. errorPath.append(&quot; path: &quot;).append(violation.getPropertyPath().toString());
  18. }
  19. error.setMessage(msgBuilder.toString());
  20. }
  21. return Response.status(error.getHttpStatusCode())
  22. .entity(error)
  23. .type(MediaType.APPLICATION_JSON)
  24. .build();
  25. }

And I have written separate method for getErrorMessage

  1. private StringBuilder getErrorMessage(ConstraintViolation&lt;?&gt; violation, StringBuilder msgBuilder) {
  2. // For default error message
  3. if (violation.getMessage().contains(&quot;{0}&quot;)) {
  4. String[] splitPath = violation.getPropertyPath().toString().split(&quot;[.]&quot;);
  5. String fieldName = splitPath[splitPath.length - 1];
  6. String messageWithFieldName = MessageFormat.format(violation.getMessage(), fieldName);
  7. msgBuilder.append((messageWithFieldName)).append(&quot;;&quot;);
  8. } else {
  9. // For customized error message
  10. msgBuilder.append(violation.getMessage()).append(&quot;;&quot;);
  11. }
  12. return msgBuilder;
  13. }

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:

  1. @NotNull
  2. private String name;
  3. message: &quot;Following constraint violations have been detected: name cannot be null or empty&quot;
  4. @NotNull(message = &quot;UserName can not be null&quot;)
  5. private String name;
  6. message: &quot;Following constraint violations have been detected: UserName can not be null&quot;
  7. @NotNull
  8. @JsonProperty(&quot;username&quot;)
  9. private String name;
  10. message: &quot;Following constraint violations have been detected: name cannot be null or empty&quot;

huangapple
  • 本文由 发表于 2020年8月27日 04:23:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/63605225.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定