Magic beans

Integrating Bean Validation with JAX-RS


Samuel Santos takes a look at one of the most rapidly changing APIs in the enterprise version of Java – JAX-RS.

Java EE 7 is the long-awaited major overhaul of Java EE 6. With each release of Java EE, new features are added and existing specifications are enhanced. Java EE 7 builds on top of the success of Java EE 6 and continues to focus on increasing developer productivity.

JAX-RS, the Java API for RESTful Web Services, is one of the fastest-evolving APIs in the Java EE landscape [1]. This is, of course, due to the massive adoption of REST-based Web services and the increasing number of applications that consume those services. In this article, we will go through the steps required to configure REST endpoints to support a JavaScript client and to handle validation exceptions to send localized error messages to the client in addition to HTTP error status codes. The source code accompanying this article is available on GitHub [2] 

Introduction to Bean Validation

JavaBeans Validation (Bean Validation) is a new validation model available as part of Java EE 7 platform. The Bean Validation model is supported by constraints in the form of annotations placed on a field, method, or class of a JavaBeans component, such as a managed bean.

Several built-in constraints are available in the javax.validation.constraints package. The Java EE 7 Tutorial lists all those built-in constraints [3].

Constraints in Bean Validation are expressed via Java annotations:

public class Person {


@Size(min = 2, max = 50)

private String name;

// ...


Bean Validation and RESTful web services

JAX-RS provides great support for extracting request values and binding them into Java fields, properties and parameters using annotations such as @HeaderParam, @QueryParam, etc. It also supports binding of request entity bodies into Java objects via non-annotated parameters (i.e., parameters that are not annotated with any of the JAX-RS annotations). However, until JAX-RS 2.0, any additional validation on these values in a resource class would have to be performed programmatically.

The last release, JAX-RS 2.0, includes a proposal to enable validation annotations to be combined with JAX-RS annotations. For example, given the validation annotation @Pattern, Listing 1 shows how path parameters can be validated:

Listing 1



public Person getPerson(


@Pattern(regexp = "[0-9]+", message = "The id must be a valid number")

String id) {

return persons.get(id);



You can of course validate entire entities instead of single fields by using the annotation @Valid. We could for example have one method that accepts a Person object and validates it, like Listing 2:

Listing 2




public Response validate(@Valid Person person) {

// ...




In Listings 1 and 2, we have used the default or hard-coded error messages, but this is both a bad practice and not flexible at all. I18n is part of the Bean Validation specification and allows us to specify custom error messages using a resource property file. The default resource file name is and must include pairs of properties/values like: person id must not be null person id must be a valid number person name must be between {min} and {max} chars long

Note: {min}, {max} refer to the properties of the constraint to which the message will be associated with.

Those defined messages can then be injected on the validation constraints as shown in Listing 3.

Listing 3




public Response createPerson(


@NotNull(message = "{}")

@Pattern(regexp = "[0-9]+", message = "{}")

String id,


@Size(min = 2, max = 50, message = "{}")

String name) {

Person person = new Person();



persons.put(id, person);

return Response.status(Response.Status.CREATED).entity(person).build();


To provide translations to other languages, one must create a new file with the translated messages, where XX is the code of the language being provided.

Unfortunately, the default Validator provider doesn’t support i18n based on a specific HTTP request. It does not take Accept-Language HTTP header into account either and always uses the default Locale, as provided by Locale.getDefault(). To be able to change the Locale using the Accept-Language HTTP header (e.g., changing the language in the browser options), a custom implementation must be provided.

Custom Validator provider

The code below intends to address this problem and has been tested with GlassFish 4. The first thing to do is to add the GlassFish dependency glassfish-embedded-all to Maven, as shown in Listing 4.

Listing 4







Next, create a ThreadLocal to store the Locale from the Accept-Language HTTP header, as shown in Listing 5. ThreadLocal variables differ from their normal counterparts, in that each thread that accesses one has its own independently initialized copy of the variable.
Listing 5


* {@link ThreadLocal} to store the Locale to be used in the message interpolator.


public class LocaleThreadLocal {

public static final ThreadLocal<Locale> THREAD_LOCAL = new ThreadLocal<Locale>();

public static Locale get() {

return (THREAD_LOCAL.get() == null) ? Locale.getDefault() : THREAD_LOCAL.get();


public static void set(Locale locale) {



public static void unset() {




Following this, create a request filter to read the Accept-Language HTTP header, like in Listing 6. The request filter is responsible for reading the first language sent by the client in the Accept-Language HTTP header and store the Locale in our ThreadLocal:
Listing 6


* Checks whether the {@code Accept-Language} HTTP header exists and creates a {@link ThreadLocal} to store the

* corresponding Locale.



public class AcceptLanguageRequestFilter implements ContainerRequestFilter {


private HttpHeaders headers;


public void filter(ContainerRequestContext requestContext) throws IOException {



Next, create a custom message interpolator to enforce a specific Locale value by bypassing or overriding the default Locale strategy. This is shown in Listing 7
Listing 7


* Delegates to a MessageInterpolator implementation but enforces a given Locale.


public class LocaleSpecificMessageInterpolator implements MessageInterpolator {

private final MessageInterpolator defaultInterpolator;

private final Locale defaultLocale;

public LocaleSpecificMessageInterpolator(MessageInterpolator interpolator, Locale locale) {

this.defaultInterpolator = interpolator;

this.defaultLocale = locale;



* Enforces the locale passed to the interpolator.



public String interpolate(String message, Context context) {

return defaultInterpolator.interpolate(message, context, this.defaultLocale);


// no real use, implemented for completeness


public String interpolate(String message, Context context, Locale locale) {

return defaultInterpolator.interpolate(message, context, locale);



GlassFish uses Jersey, the reference implementation for JAX-RS, which allows customization of the Validator used in validation of resource classes/methods using ValidationConfig class and exposing it via ContextResolver<T> mechanism [4]. Configure the Validator to use our custom message interpolator, like in Listing 8.
Listing 8


* Custom configuration of validation. This configuration can define custom:

* <ul>

* <li>MessageInterpolator - interpolates a given constraint violation message.</li>

* <li>TraversableResolver - determines if a property can be accessed by the Bean Validation provider.</li>

* <li>ConstraintValidatorFactory - instantiates a ConstraintValidator instance based off its class.

* <li>ParameterNameProvider - provides names for method and constructor parameters.</li> *

* </ul>



public class ValidationConfigurationContextResolver implements ContextResolver<ValidationConfig> {

private static final Logger LOGGER = Logger.getLogger(ValidationConfigurationContextResolver.class.getName());


private HttpHeaders headers;


* Get a context of type {@code ValidationConfiguration} that is applicable to the supplied type.


* @param type the class of object for which a context is desired

* @return a context for the supplied type or {@code null} if a context for the supplied type is not available from

* this provider.



public ValidationConfig getContext(Class<?> type) {

final ValidationConfig config = new ValidationConfig();

config.setMessageInterpolator(new LocaleSpecificMessageInterpolator(Validation.byDefaultProvider().configure()

.getDefaultMessageInterpolator(), headers.getAcceptableLanguages().get(0)));

return config;




Mapping Exceptions

When validation fails, an exception is thrown by the container by default and a HTTP error is returned to the client.

Bean Validation specification defines a small hierarchy of exceptions (they all inherit from ValidationException) that could be thrown during initialization of validation engine or (for our case more importantly) during validation of input/output values (ConstraintViolationException). If a thrown exception is a subclass of ValidationException except ConstraintViolationException then this exception is mapped to a HTTP response with status code 500 (Internal Server Error). On the other hand, when a ConstraintViolationException is thrown, two different status codes could be returned:

  • 500 (Internal Server Error) if the exception was thrown while validating a method return type.
  • 400 (Bad Request) 

This behavior can be customized to allow us to add error messages to the response that is returned to the client, like in Listing 9.

 * {@link ExceptionMapper} for {@link ValidationException}.
 * <p>
 * Send a list of {@link ValidationError} instances in {@link Response} in addition to HTTP 400/500 status code.
 * Supported media types are: {@code application/json} / {@code application/xml} (if appropriate provider is registered
 * on server).
 * </p>
public class ValidationExceptionMapper implements ExceptionMapper<ValidationException> {

    private static final Logger LOGGER = Logger.getLogger(ValidationExceptionMapper.class.getName());

    private Configuration config;

    private Provider<Request> request;

    public Response toResponse(final ValidationException exception) {
        if (exception instanceof ConstraintViolationException) {
            LOGGER.log(Level.FINER, "Following ConstraintViolations has been encountered.", exception);
            final ConstraintViolationException cve = (ConstraintViolationException) exception;
            final Response.ResponseBuilder response = Response.status(getStatus(cve));

            // Entity
            final List<Variant> variants = Variant.mediaTypes(MediaType.APPLICATION_XML_TYPE,
            final Variant variant = request.get().selectVariant(variants);
            if (variant != null) {
                    new GenericEntity<List<ValidationError>>(
                            new GenericType<List<ValidationError>>() {}.getType()

        } else {
            LOGGER.log(Level.WARNING, "Unexpected Bean Validation problem.", exception);

            return Response.serverError().entity(exception.getMessage()).build();

    private List<ValidationError> getEntity(final Set<ConstraintViolation<?>> violations) {
        final List<ValidationError> errors = new ArrayList<ValidationError>();

        for (final ConstraintViolation<?> violation : violations) {
            errors.add(new ValidationError(getInvalidValue(violation.getInvalidValue()), violation.getMessage(),
                    violation.getMessageTemplate(), getPath(violation)));

        return errors;

    private String getInvalidValue(final Object invalidValue) {
        if (invalidValue == null) {
            return null;

        if (invalidValue.getClass().isArray()) {
            return Arrays.toString((Object[]) invalidValue);

        return invalidValue.toString();

    private Response.Status getStatus(final ConstraintViolationException exception) {
        return getResponseStatus(exception.getConstraintViolations());

    private Response.Status getResponseStatus(final Set<ConstraintViolation<?>> constraintViolations) {
        final Iterator<ConstraintViolation<?>> iterator = constraintViolations.iterator();

        if (iterator.hasNext()) {
            return getResponseStatus(;
        } else {
            return Response.Status.BAD_REQUEST;

    private Response.Status getResponseStatus(final ConstraintViolation<?> constraintViolation) {
        for (final Path.Node node : constraintViolation.getPropertyPath()) {
            final ElementKind kind = node.getKind();

            if (ElementKind.RETURN_VALUE.equals(kind)) {
                return Response.Status.INTERNAL_SERVER_ERROR;

        return Response.Status.BAD_REQUEST;

    private String getPath(final ConstraintViolation<?> violation) {
        final String leafBeanName = violation.getLeafBean().getClass().getSimpleName();
        final String leafBeanCleanName = (leafBeanName.contains("$")) ? leafBeanName.substring(0,
                leafBeanName.indexOf("$")) : leafBeanName;
        final String propertyPath = violation.getPropertyPath().toString();

        return leafBeanCleanName + (!"".equals(propertyPath) ? '.' + propertyPath : "");
Listing 9 is an implementation of the ExceptionMapper interface which maps exceptions of the type ValidationException. This exception is thrown by the Validator implementation when the validation fails. If the exception is an instance of ConstraintViolationException we send a list of ValidationError instances in the response in addition to HTTP 400/500 status code. This ensures that the client receives a formatted response instead of just the exception being propagated from the resource.

The ValidationError class is a very simple validation error entity, shown in Listing 10.

Listing 10


* Default validation error entity to be included in {@code Response}.



public final class ValidationError {

private String invalidValue;

private String message;

private String messageTemplate;

private String path;

public ValidationError() {


public ValidationError(final String invalidValue, final String message, final String messageTemplate,

final String path) {

this.invalidValue = invalidValue;

this.message = message;

this.messageTemplate = messageTemplate;

this.path = path;


// Getters and Setters...



The produced output looks just like the following (in JSON format):

{"invalidValue":"test","message":"The id must be a valid number","messageTemplate":"The id must be a valid number","path":""}

Running and testing

To run the application used for this article, build the project with Maven, deploy it into a GlassFish 4 application server, and point your browser to http://localhost:8080/jaxrs-beanvalidation-javaee7/.

Alternatively, you can run the tests from the class PersonsIT which are built with Arquillian and Junit [5] [6]. Arquillian will start an embedded GlassFish container automatically, so make sure you do not have another server running on the same ports.









Inline Feedbacks
View all comments