Martin Čuka
Martin Čuka

Reputation: 18468

How to tell hibernate validator to validate only one annotation?

Is it possible to tell hibernate validation to validate only one particular annotation ?
I've created custom annotation which use javax.validation.ConstraintValidator so far so good.
However when I want to manually validate Object using

javax.validation.Validator.validate(myOjbect);

it will validate all annotations including @NotNull, @Size... Is there an elegant way to override this behaviour so I can choose which annotations to validate ?

Upvotes: 0

Views: 1395

Answers (1)

Selaron
Selaron

Reputation: 6184

I can't find a way to limit validation to a particular annotation without modifying the validated class. You can limit it to a property by calling Validator##validateProperty(object, propertyName, ...) but the equivalent to explicitly limit it to a set of annotations requires to assign groups to annotations:

What seemes to work is this:

  1. Create an interface for each group of annotations you want to validate.
  2. Specify that interface for groups property of each annotation to validate with this group. If the annotation also must be validated by default, add the Default interface either.
  3. Add the interface to validator invocations.

An example:

import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.validation.groups.Default;

public class SomeTest {

    public static void main(String[] args) {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();

        Cat a = new Cat(null);
        // invalid: name is null
        output(validator.validate(a), a);

        Cat b = new Cat("?");
        // invalid: name too short
        output(validator.validate(b), b);

        // valid: only @NotNull is evaluated, @Size does not matter.
        output(validator.validate(b, NotNullName.class), b);

        // invalid: only @NotNull is evaluated, @Size does not matter. Name is null.
        output(validator.validate(a, NotNullName.class), a);
    }

    /**
     * Output validation result.
     *
     * @param validate
     *            the validate
     */
    private static void output(Set<ConstraintViolation<Cat>> validationResult, Cat cat) {
        if (validationResult.isEmpty()) {
            System.out.println(cat + " is valid!");
        } else {
            System.out.println(cat + " is invalid!\n" + validationResult);
        }
    }

    // no need to implement an interface - just name it for annotation groups attribute:
    public static class Cat {
        @NotNull(groups = { NotNullName.class, Default.class })
        @Size(min = 3, max = 45)
        private String name;

        public Cat(String name) {
            super();
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            StringBuilder builder = new StringBuilder();
            builder.append("Cat [");
            if (name != null) {
                builder.append("name=");
                builder.append(name);
            }
            builder.append("]");
            return builder.toString();
        }

    }

    public static interface NotNullName {
        // no members needed here
    }
}

Output:

Cat [] is invalid!
[ConstraintViolationImpl{interpolatedMessage='darf nicht null sein', propertyPath=name, rootBeanClass=class SomeTest$Cat, messageTemplate='{javax.validation.constraints.NotNull.message}'}, ConstraintViolationImpl{interpolatedMessage='darf nicht null sein', propertyPath=name, rootBeanClass=class SomeTest$Cat, messageTemplate='{javax.validation.constraints.NotNull.message}'}]
Cat [name=?] is invalid!
[ConstraintViolationImpl{interpolatedMessage='Länge muss zwischen 3 und 45 liegen', propertyPath=name, rootBeanClass=class SomeTest$Cat, messageTemplate='{javax.validation.constraints.Size.message}'}]
Cat [name=?] is valid!
Cat [] is invalid!
[ConstraintViolationImpl{interpolatedMessage='darf nicht null sein', propertyPath=name, rootBeanClass=class SomeTest$Cat, messageTemplate='{javax.validation.constraints.NotNull.message}'}]

Upvotes: 1

Related Questions