1

I have created a custom validator annotation and I want to use it only when username is not null. I have an endpoint where @RequestParam String username is not required and everything is fine there. Problem is with annotation, because it validates username regardless of the existence of a variable. I want to validate username only If username exists. Here is code:

@RequestMapping(value = "", method = RequestMethod.GET)
public ResponseEntity get( @RequestParam(value = "username", required = false) @ExistAccountWithUsername(required = false) String username) {
    if (username != null) {
        return getUsersByUsername(username);
    }
    return getAllUsers();
}

Annotation:

@Filled
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ExistAccountWithUsernameValidator.class)
public @interface ExistAccountWithUsername {
  boolean required() default true;
  String message() default "There is no account with such username";
  Class<?>[] groups() default {};
  Class<? extends Payload>[] payload() default {};
}

Validator:

public class ExistAccountWithUsernameValidator implements ConstraintValidator<ExistAccountWithUsername, String> {

  private UserService userService;
  private boolean required;

  public ExistAccountWithUsernameValidator(UserService userService) {
    this.userService = userService;
  }

  public void initialize(ExistAccountWithUsername constraint) {
    required = constraint.required();
  }

  public boolean isValid(String username, ConstraintValidatorContext context) {
    if (!required) {
        return true;
    }
    return username != null && userService.findByUsername(username).isPresent();
  }

}

EDIT: I have added parameter. @Filled is @NotBlank and @NotNull. Updated code. It return:

"errors": [
    "must not be blank",
    "must not be null"
]

2 Answers 2

3

In your custom validator you can just perform a null check as below :

@Override
public boolean isValid(String value, ConstraintValidatorContext context)
{
    if(value == null)
        return true;
    return someFurtherCheck(value, context);
}

This way, it will be accepted if null, and checked if otherwise. Also, if you want to reuse this validator elsewhere where null value should return false, you can either add an @NotNull on top of your field to be checked as well, or add parameter in your validator annotation that stipulates wether null value should be accepted or not.

The latest method can be done as following :

@ExistAccountWithUsername class :

public @interface ExistAccountWithUsername {


String message() default "your message";
Class[] groups() default {};

Class[] payload() default {};

boolean acceptNull() default true;

}

ValidatorClass :

public class ExistAccountWithUsernameValidator implements ConstraintValidator<ExistAccountWithUsername, String> {

private boolean acceptNull;

@Override
public void initialize(ExistAccountWithUsername constraintAnnotation){
    acceptNull = constraintAnnotation.acceptNull();
}

@Override
public boolean isValid(String value, ConstraintValidatorContext context)
{
    if(value == null)
       return acceptNull;
    return someFurtherCheck(value, context);
}


 }

So now when you don't want to accept null values for this validator, just use @ExistAccountWithUsername(acceptNull = false) instead of just @ExistAccountWithUsername

Sign up to request clarification or add additional context in comments.

8 Comments

@Nikolas I want to use this annotation in other cases too. I have added parameter with boolean required field, but my annotation have annotations like @NotNull and @NotBlank and they validate even If I return true in my custom validator
Then in this case, you can add a parameter to your @ExistsAccountWithUsername annotation to stipulate how it should handle null values, as explained in my answer. I will update it to provide a code example.
I updated the answer, it should fit your use case now
I have done like that. Look at my updated code and validation error. I have to totally off validation if required = false otherwise it checks other annotations that are "on" this annotation
And if @RequestParam is not required it doesn't mean that I should pass empty or null username because i will get a null pointer exception so I need to check@NotNull and @NotBlank
|
1

I see you have probably created validating annotation @ExistAccountWithUsername already. Reuse it and add the condition to ConstraintValidator::isValid method.

@Override
public boolean isValid(String username, ConstraintValidatorContext context) {
    if (username == null) {
        return true;  // is valid
    } else {
        // ... further validation in case the username is not null
    }
}

In case I misunderstood your @ExistAccountWithUsername annotation. There is a very detailed guide at Baeldung's article Method Constraints with Bean Validation 2.0.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.