Skip to content


Automatic model validation using Jersey, Jackson, and Hibernate Validator

So you have a RESTful Java webapp built using Jersey, some POJO/JAXB models that you’d like to serialize using Jackson, and think it’d be sweet to validate models using annotations (JSR 303 – Bean Validation)? And you like your objects to be immutable (Effective Java Item #15). You’ve come to the right place. Hibernate Validator is the reference implementation for JSR 303 and arguably the best currently available, so we’ll use it along with Jersey and Jackson to form the backbone of this recipe.

The general idea behind the ValidatingJacksonJsonProvider is that we can annotate any of the parameters used in our resource classes with @Valid to have the object automatically validated during the Jackson JSON serialization process.

So, first, annotate your POJO/JAXB object with some constraints, like @Min(0) and @NotEmpty.

package com.mydomain.myapp.model;
 
import javax.validation.constraints.Min;
 
import com.fasterxml.jackson.annotation.JsonProperty;
 
import org.hibernate.validator.constraints.NotEmpty;
 
public class MyModel {
    private final long id;
    private final String name;
 
    public MyModel(@JsonProperty("id") long id, @JsonProperty("name") String name) {
        this.id = id;
        this.name = name;
    }
 
    public @Min(0) getId() {
        return id;
    }
 
    public @NotEmpty getName() {
        return name;
    }
}

Now we can validate MyModel it in a Jersey resource class. For example, validating myModel before saving a new record to the database.

import javax.validation.Valid;
import javax.ws.rs.POST;
 
import com.mydomain.myapp.model.MyModel;
 
public class MyResource {
    @POST
    public createMyModel(@Valid MyModel myModel) {
        ...
    }
}

The code to implement this recipe follows. Just add this alongside your other Jersey providers (e.g., in your resources package). Its essentially a forwarding MessageBodyReader, MessageBodyWriter that delegates to the standard JacksonJsonProvider, and hooks validation into the readFrom call.

One way to make this smarter is to throw a RuntimeException that’s registered with a Jersey ExceptionMapper. Instead of always responding with a plain-text response, this will allow Jersey to handle content-negotiation and return an error response in the appropriate format. How else could you improve this technique?

Posted in Tutorials.


9 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Miguel Andrade says

    Correct me if I’m wrong, but I don’t like injecting the JacksonProvider here. I would like to delegate the flow back to JAX-RS and not to Jackson in particular. This way this validation provider would be independent of the serializer.

    Please check this post: http://weblogs.java.net/blog/ljnelson/archive/2010/04/28/pushing-jersey-limit

    The author uses:
    @Context
    private Providers providers;

    and then:

    final MessageBodyWriter delegate = this.providers.getMessageBodyWriter(TheClass.class, TheClass.class, annotations, mediaType);

    It appears to be a more generic and standard way to obtain the correct MessageBodyWriter. Using your approach you might be even overriding @Consumes or @Produces annotations and forcing the use of Jackson, but I’m not sure.

    Thank you very much for your post.
    Looking forward to have a “plug n play” JSR-303 provider for JAX-RS. : )

  2. codyaray says

    @Miguel Very interesting. I didn’t consider delegating back to JAX-RS to make this more generic, but I believe that would work as well. It so happens that I only use JSON serialization in the project I extracted this from, so I never had the need… but I’ll definitely keep this in mind in the future.

    Wow, that’s some hairy code in the post you linked. With mixed dependency-injection styles, ThreadLocals, and reflection-based instance creation, this would be crazy hard to unit test. But cool that it seems to work for the author, at least.

    If I ever update this code to to support a generic serialization type, I’ll look at delegating back to JAX-RS and post an update here. Heck, I might just do it for fun… I sure hope that it’ll be easier than the JAXB wrapper hell he went through though.

    PS – This validating provider still handles content-type negotiation appropriately because its only used for JSON requests. Notice the @Consumes and @Produces annotations on the ValidatingJacksonJsonProvider.

    • Miguel Andrade says

      What I was trying to do wasn’t so simple. I ended up in an infinite loop because JAX-RS always returned my custom MessageBodyWriter. It makes sense since it always uses the first it finds. We need another thing that isn’t a MessageBodyWriter/Reader. These are for marshalling and unmarshalling purposes. JAX-RS 2.0 introduces Interceptors which maybe more suitable for cases like this (although JAX-RS 2.0 introduces Validation itself).

      I’ll try to accomplish this task with some AOP, maybe.

  3. codyaray says

    Cool. Let me know how it goes. Sounds like something I’ll need to keep in mind if I use the delegate-to-JAXRS model.

    Didn’t know that JAX-RS 2.0 introduced Validation. That’s sweet.

  4. Miguel Andrade says

    One more thing.

    JSR-303 has support for groups. Example here: http://www.jroller.com/eyallupu/entry/jsr_303_beans_validation_using

    This is important because you probably don’t want to do the same kind of validation across your entire application. An example is when you want to do a partial update (PUT). Or, for example, an id property must be null in a POST request but non-null everywhere else.

    Your MessageBodyWriter/Reader could check the method for the group class present in the annotation @ValidateRequest(groups = PartialUpdateGroup.class) and then apply the appropriate validation. See example of this annotation usage here: @ValidateRequest(groups = PartialUpdateGroup.class).

    Validation in REST WebServices appears to be quite challenging. : )
    Haven’t found a complete example yet.

    Just to let you know.
    Hope I’ve been helpful. Thank you.

  5. Miguel Andrade says

    Oops, forgot the last link: http://docs.jboss.org/seam/3/rest/latest/reference/en-US/html/rest.validation.html

  6. Billy Yuen says

    Why are you using Google Guice? BTW, Both delgate and validator are null in my case. So it does not work. I am using Jersey 1.x.

  7. codyaray says

    Billy – I’m using Google Guice to inject my dependencies, so that I don’t have to manually setup the object hierarchy. If you don’t like it, you can manually initialize the object. Those values should only be null if they are not injected correctly (though normally Guice throws an error if it can’t find a value to be injected).



Some HTML is OK

or, reply to this post via trackback.

 



Log in here!