Earlier this month, we released Hibernate Validator 6.1.1.Final which includes some nice improvement to our localization support.

This is a recommended upgrade for everyone using Hibernate Validator and it is a drop-in replacement for 6.1.0.Final.

What’s new

Localization support improvement

Hibernate Validator has always been built with localization in mind but, if we had translations of our constraint violation messages in several languages, supporting validation in your applications required to use a custom MessageInterpolator resolving the locale you wanted to use and delegating to the default one. Otherwise, Hibernate Validator would simply use the default locale of the system.

This wasn’t very practical and 6.1.1.Final introduces a specific SPI to handle localization with more flexibility: LocaleResolver.

A good example of a LocaleResolver is the one we now have in Quarkus. It uses the ResteasyContext to extract the Accept-Language header from the request and use the best locale available.

public class ResteasyContextLocaleResolver implements LocaleResolver {

    @Override
    public Locale resolve(LocaleResolverContext context) {
        Optional<List<LanguageRange>> localePriorities = getAcceptableLanguages();
        if (!localePriorities.isPresent()) {
            return context.getDefaultLocale();
        }

        List<Locale> resolvedLocales = Locale.filter(localePriorities.get(), context.getSupportedLocales());
        if (resolvedLocales.size() > 0) {
            return resolvedLocales.get(0);
        }

        return context.getDefaultLocale();
    }

    private Optional<List<LanguageRange>> getAcceptableLanguages() {
        HttpHeaders httpHeaders = ResteasyContext.getContextData(HttpHeaders.class);
        if (httpHeaders != null) {
            List<String> acceptLanguageList = httpHeaders.getRequestHeader("Accept-Language");
            if (acceptLanguageList != null && !acceptLanguageList.isEmpty()) {
                return Optional.of(LanguageRange.parse(acceptLanguageList.get(0)));
            }
        }

        return Optional.empty();
    }
}

To make use of this LocaleResolver, initialize your ValidatorFactory as follows:

ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
    .configure()
    .localeResolver(yourLocaleResolver)
    .locales(Locale.ENGLISH, Locale.GERMAN, Locale.FRENCH, Locale.ITALIAN)
    .defaultLocale(Locale.FRENCH)
    .buildValidatorFactory();

There are a couple of noticeable things:

  • You will need to pass the list of locales you want to support i.e. the ones for which you have proper translations for your constraint messages;

  • You can define a default locale different from the system default locale.

This new SPI is still incubating so give it a try and give us your feedback!

Full changelog

The complete list of fixed issues can be found on our JIRA.

Getting 6.1.1.Final

To get the release with Maven, Gradle etc. use the following GAV coordinates:

  • org.hibernate.validator:hibernate-validator:6.1.1.Final

  • org.hibernate.validator:hibernate-validator-cdi:6.1.1.Final

  • org.hibernate.validator:hibernate-validator-annotation-processor:6.1.1.Final

Note that the group id has changed from org.hibernate (Hibernate Validator 5 and earlier) to org.hibernate.validator (from Hibernate Validator 6 onwards).

Alternatively, a distribution bundle containing all the bits is provided on SourceForge (TAR.GZ, ZIP).

If you want to benefit from the new features of this version on WildFly, we also provide WildFly patches for WildFly 18 and WildFly 17.0.1. You can read about how to apply such patches here.

Feedback, issues, ideas?

To get in touch, use the usual channels:


Back to top