[null, null, null, {"document_url": "http://in.relation.to/2017/03/02/adding-custom-constraint-definitions-via-the-java-service-loader/", "unformatted_src": "/images/external_validators_project_structure_duration.png", "src": "https://in.relation.to/images/external_validators_project_structure_duration.png", "formatted_filename": "external validators project structure duration", "alt_text": "project structure, align=", "rendered_width": 400}, null, {"document_url": "http://in.relation.to/2017/03/02/adding-custom-constraint-definitions-via-the-java-service-loader/", "unformatted_src": "/images/external_validators_project_structure_threeten_extra.png", "src": "https://in.relation.to/images/external_validators_project_structure_threeten_extra.png", "formatted_filename": "external validators project structure threeten extra", "alt_text": "project structure, align=", "rendered_width": 400}, null]
Adding custom constraint definitions via the Java service loader

Posted by Marko Bekhta    |    Mar 2, 2017    Hibernate Validator Discussions

Today we’ll be talking about Hibernate Validator and how you can provide your own constraints and/or validators in a fully self-contained manner. Meaning packaging it all into its own JAR file, in a way that others can use your library by simply adding it to the classpath.

This functionality is based on Hibernate Validator usage of Java’s ServiceLoader mechanism that allows to register additional constraint definitions. But more on the details later.

What can be a real life scenario for building your own library with constraints and sharing it? Well, let’s say that you are building some library with data classes that user might want to validate. As it may be tough to keep track of all such libraries and write/maintain all those constraints for them - Hibernate Validator provides authors of such libraries a possibility to write and share their own validation extensions. Which can be picked up by Hibernate Validator and used to validate your data classes.

Also this ServiceLoader mechanism allows to solve another problem. As you are trying to be a good developer and provide end users of your library only with the relevant classes and hide implementation details from them, you may not want to expose your validator implementation by mentioning it in the validatedBy() parameter of the @Constraint annotation. By using the approach described in this post you can achieve all these thing.

For our examples we will be creating Maven projects with two modules - one will contain validators and represent a "library" that can be shared, another module will be a consumer of this library and will contain some tests.

Enough of the talking, let’s validate some beans! That’s why we all gathered here, right? :)

Using custom annotations and validators

First let’s consider a case of adding your own constraint annotation and a corresponding validator.

Time, it needs time …​

While Hibernate Validator 5.4 supports a wide range of the Java 8 date/time API (and Bean Validation 2.0 will move this support to the specification level), there are some types not supported, one of them being Duration. This type is not describing a point in time so the regular date/time constraints (@Future / @Past) do not make sense for it. So if for instance we wanted to validate that a given duration has a specified minimum length, a new constraint is needed. Let’s call it @DurationMin.

Our new constraint annotation might look like this:


Now that we have an annotation, we need to create a corresponding constraint validator. To do that you need to implement the ConstraintValidator<DurationMin, Duration> interface, which contains two methods:

An implementation might look like this:


As we are creating a new constraint annotation, we should also provide a default message for it. This can be done by placing a ContributorValidationMessages.properties property file in the classpath. This property file should contain a key/message pair, where key is the one used in annotation declaration (in our case it’s com.acme.validation.constraints.DurationMin.message) and message is the one you would like to show when validation fails. Our property file looks like so:


The bundle ContributorValidationMessages is queried by Hibernate Validator if the standard ValidationMessages bundle doesn’t contain a given message key, allowing library authors to provide default messages for their constraints as part of their JAR.

If you leave everything else as is, your constraint annotation will live its own life without knowing about the presence of validator. Hibernate Validator will not know of the validator as well. So to make sure that Hibernate Validator discovers your DurationMinValidator, you need to create the file META-INF/services/javax.validation.ConstraintValidator and put the fully qualified name of the validator implementation in it:


After all of this, your new constraint annotation on Duration elements can be used like this:


The project structure should look similar to next one: The whole source code presented here can be found in the hibernate-demos repository on GitHub.

Use standard constraints for non standard classes

Now let’s consider the case where you would want a standard Bean Validation constraint to support some other type, besides the ones that are already supported.

ThreeTen Extra types validation

As we were talking about date/time related validation, let’s stay on the same topic for this example as well. In this section we will look at ThreeTen Extra types - a great library that provides additional date and time classes to complement those already present in Java.

Bean Validation provides support for validating temporal types via the @Past/@Future annotations. So we would want to use these annotations on ThreeTen Extra types as well. To keep this example simple we will provide validators only for YearWeek and YearQuarter.

Let’s start with implementing ConstraintValidator<Future, YearWeek> interface:


The next step is to provide a list of implemented validators in META-INF/services/javax.validation.ConstraintValidator file:


After this we can package it all in a JAR file and we are ready to use our validators and share them with the world!

In the end our project structure should look similar to this: Now you can place @Past/@Future annotations on YearQuarter and YearWeek types like this:


You also can find this example at GitHub.


So, as you can see, custom constraint validators can be built and shared in a fully self-contained way. And it can be done in a few simple steps:
