Reputation: 253
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.
Upvotes: 2
Views: 2266
Reputation: 253
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"
Upvotes: 0
Reputation: 7957
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.
Upvotes: 1