Remko de Jong Remko de Jong - 1 month ago 13
Java Question

Hibernate Validator With Validation groups for Serialisation With Write Access

I have an endpoint where a user can register with her email/password. However I, want to check that the password is not empty, but I also want to only deserialize the password, because I do not want to send it back to the client.

Domain

public class User {
@NotEmpty
private String email;
@JsonProperty(access = Access.WRITE_ONLY)
@NotEmpty
private String password;

// Getters and setters
...
}


Endpoint

@Path("/register")
@POST
public Response register(@Valid User user) {
...
}


Instead of the
Access.WRITE_ONLY
I've also tried
@JsonIgnore
on the getter and
@JsonProperty
on the setter.

The problem is Hibernate Validator keeps complaining that the password is empty, even when I POST a user with password set:

"{"errors":["password may not be empty"]}"


How can I fix this? Or do I have to implement my own NotEmpty validation logic in the endpoint?

Answer

This can be done using validation groups. Here is how you would achieve this:

public class GroupValidationTest {


    public static void main(String[] args) {
        Validator v = Validators.newValidator();


        Model m = new Model();
        m.user = "Harry";
        m.password = "Potter";

        Set<ConstraintViolation<Model>> validate = v.validate(m, INPUT.class);
        System.out.println(validate.size());

        validate = v.validate(m, INPUT.class, OUTPUT.class);
        System.out.println(validate.size());

        validate = v.validate(m, OUTPUT.class);
        System.out.println(validate.size());

        m.password = null;

        validate = v.validate(m, INPUT.class, OUTPUT.class);
        System.out.println(validate.size());

        validate = v.validate(m, OUTPUT.class);
        System.out.println(validate.size());
    }

    public static class Model {

        @NotEmpty(groups={INPUT.class, OUTPUT.class})
        public String user;

        @NotEmpty(groups={INPUT.class})
        public String password;

    }

    public interface INPUT {}
    public interface OUTPUT {}

}

This outputs:

0 -> Full object, validate INPUT 
0 -> Full object, validate INPUT + OUTPUT
0 -> Full object, validate OUTPUT
1 -> null password, validate INPUT + OUTPUT
0 -> null password, validate OUTPUT

Explenation:

Hibernate validator framework supports groups for validation constraints. They are used to tell the validator which groups to validate in a specific validation attempt. You can read all about it here:

https://docs.jboss.org/hibernate/validator/4.2/reference/en-US/html/validator-usingvalidator.html#example-group-interfaces

What I did in my code example is:

  • Define 2 groups INPUT and OUTPUT
  • Mark the user property to be validated for both groups
  • Mark the password property to be validated only on input

For the REST aspect (different question), usually validation of input and ouput is done by an interceptor, typically the MessageBodyReader and Writer class. These are responsible for reading user input and writing it out. You can read about that on the jersey docs page.

You can then implement your own validation reader/writer that knows to only validate INPUT when reading user input, while only validating OUTPUT when writing the serialised body back.

I hope that helps,

artur

Comments