user871611
user871611

Reputation: 3462

Cross field validation (JSR 303) problem

I have a simple bean, i.e.:

public class MyBean {

  private boolean selected;

  private String someString;

  ...
}

So if selected is true, I want someString to be @NotNull etc. .

Any hints, links how to achieve this behaviour?

Thanks Jonny

Upvotes: 3

Views: 2023

Answers (2)

Jakub Jirutka
Jakub Jirutka

Reputation: 10837

If you’re using Spring Framework then you can use Spring Expression Language (SpEL) for that. I’ve wrote small library that provides JSR-303 validator based on SpEL that makes cross-field validations very easy. Take a look at https://github.com/jirutka/validator-spring.

And there’s example for your case:

@SpELAssert(value = "someString != null", applyIf = "selected",
            message = "{validator.missing_some_string}")
public class MyBean {

    private boolean selected;

    private String someString;

  ...
}

Actually this was too easy. Try something more interesting, maybe an equality of password fields when one of them is not null.

@SpELAssert(value = "password.equals(passwordVerify)",
            applyIf = "password || passwordVerify",
            message = "{validator.passwords_not_same}")
public class User {

    private String password;
    private String passwordVerify;
}

And you can even use your own “helper methods” in these expressions!

Compared to Hibernate Validator’s @ScriptAssert annotation, this is pure Java solution, it’s not using any JSR-223 compliant scripting language which may be a little problematic. On the other side, this solution is interesting only for Spring-based applications.

Upvotes: 3

Kai
Kai

Reputation: 39651

You could do this by annotating MyBean with a custom validator, for example:

@ValidMyBean
public class MyBean {

  private boolean selected;

  private String someString;

  ...
}

ValidMyBean:

@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MyBeanValidator.class)
public @interface ValidMyBean {

    boolean allViolationMessages() default true;

    Class<?>[] constraints() default {};

    Class<?>[] groups() default {};

    String message() default "{ValidMyBean.message}";

    Class<? extends Payload>[] payload() default {};
}

MyBeanValidator:

public final class MyBeanValidator implements
        ConstraintValidator<ValidMyBean, MyBean> {

    @Override
    public void initialize(
            @SuppressWarnings("unused") final ValidMyBean constraintAnnotation) {
    }

    @Override
    public boolean isValid(final MyBean value,
            final ConstraintValidatorContext context) {

        boolean isValid = true;
        //your validation here

        return isValid;
    }
}

Upvotes: 2

Related Questions