Hibernate Validator 7 についてきちんと書いてある文献が少ない

There are few references that properly describe Hibernate Validator 7

If you want to use Hibernate Validator 7, you must use jakarta.validation packages.
If you want to use javax.validation's annotations, you must use Hibernate Validator 6 packages (e.g. org.hibernate.validator:hibernate-validator:6.2.3.Final).

English content are below.


Hibernate Validator 7 についてきちんと書いてある文献が少ない

少ないので、はまった。時間がかかった。なので記しておく。

要するに、

  • javax.validation を使うのであれば、それは最新版では javax.validation:validation-api:2.0.1.Final であり、バリデータは org.hibernate.validator:hibernate-validator:6.2.3.Final で実装されている。
  • jakarta.validation を使うのであれば、それは最新版では jakarta.validation:jakarta.validation-api:3.0.0 であり、バリデータは org.hibernate.validator:hibernate-validator:7.0.4.Final で実装されている。

と理解している。間違っているかどうかは知らない。


閑話:
日本語では
Spring FrameworkでValidationを実装する際に泥沼にハマる...
https://ts0818.hatenablog.com/entry/2021/06/09/180659
Hibernate ValidatorでBean Validationしてみる
https://ts0818.hatenablog.com/entry/2021/04/03/161310
この方の文献が正しく、かつ読みやすいように思う。

JavaでGC(Garbage Collection)のログのオプションでハマる
https://ts0818.hatenablog.com/entry/2021/01/02/185016
Javaでjava.lang.Objectのequals(Object obj)、hashCode()は何故@Overrideする必要があるのか
https://ts0818.hatenablog.com/entry/2020/12/21/224510

等は、普段は飛ばしてしまいそうだが、大事なポイントだと思う。


Gradle を使っているので、Gradle の文法で書くが、それに限らない。

dependencies {
    // https://mvnrepository.com/artifact/javax.validation/validation-api
    implementation("javax.validation:validation-api:2.0.1.Final")

    testImplementation("org.junit.jupiter:junit-jupiter:5.8.2")
    // https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator
    testRuntimeOnly("org.hibernate.validator:hibernate-validator:6.2.3.Final")// OK
    // testRuntimeOnly("org.hibernate.validator:hibernate-validator:7.0.4.Final")// NG
    // https://mvnrepository.com/artifact/org.glassfish/javax.el
    testRuntimeOnly("org.glassfish:javax.el:3.0.0")
}

こんな感じで依存関係の記述を行っているプロジェクトがあったとして、Hibernate Validator 7 があると、あることだけは知っていれば、

testRuntimeOnly("org.hibernate.validator:hibernate-validator:7.0.4.Final")

のように記述したくなるだろう。私はなる。

ところがそうすると動かないのである。

Stack overflow に

Unable to create a Configuration, because no Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath
https://stackoverflow.com/questions/36329001/unable-to-create-a-configuration-because-no-bean-validation-provider-could-be-f

という質問がある。

質問者は

<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>7.0</version>
</dependency>

という設定にしていて、

javax.validation.ValidationException: Unable to create a Configuration, because no Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:271)
at org.springframework.validation.beanvalidation.LocalValidatorFactoryBean.afterPropertiesSet(LocalValidatorFactoryBean.java:223)
at org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean.afterPropertiesSet(OptionalValidatorFactoryBean.java:40)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:667)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:633)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:552)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:493)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
at javax.servlet.GenericServlet.init(GenericServlet.java:158)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1241)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1154)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1041)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4944)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5230)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

このようなエラーがでたという。私も似たようなエラーが発生して、先に進めなかった。

javax.validation.ValidationException

実はここがポイントの1つである。

回答者の一人は

In my case, I moved to Hibernate 7.x but had an old explicit dependency on:

といいながら、`javax.validation:validation-api:2.0.1.Final`
を「外す」ことを勧めている。

別の回答者は

I made it work downgrading the dependency of hibernate-validator from version `7.0.2.Final` to `6.0.13.Final`.
としている。

ここがポイントなのである…


よくある文献では、`@Size` アノテーションを使おうと思えば、

import javax.validation.constraints.Size;

と `import` 宣言するように促しており、実際それで動作する。

しかし、しかしなのだ…

Hibernate Validator Migration Guide
https://hibernate.org/validator/documentation/migration-guide/
を見てほしい。

7.0.0.CR1
Jakarta EE 9 (a.k.a. the big jakarta.* package change)
...
See https://in.relation.to/2020/12/08/hibernate-validator-700-62-cr1-released/ for more details.

ということで、https://in.relation.to/2020/12/08/hibernate-validator-700-62-cr1-released/ を見てみよう。

Jakarta EE 9 is an iterative release on top of EE 8 with the main purpose of renaming all the `javax.` packages to the `jakarta.` packages.

`javax.` 開始なのは `jakarta.` になる…とある。後も読んでおいて欲しい。とにかく、`javax.` はもう古いものになっていくのである。

Java EE 8 という時代(いつかは知らない)の日本語文献としては
Bean Validation 2.0 を Java SE のプログラムに導入する
https://qiita.com/niwasawa/items/7ab89140eb1b0c5b5eea
があり、

  • javax.validation:validation-api (Bean Validation API)
  • org.hibernate.validator:hibernate-validator (Bean Validation API を実装したライブラリ)
  • org.glassfish:javax.el (Unified Expression Language を実装したライブラリ)

この3つが必要なようだ。欠けていると

javax.validation.NoProviderFoundException: Unable to create a Configuration, because no Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.

javax.validation.ValidationException: HV000183: Unable to initialize 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead

のようなエラーがでるとのことだ。


There are few references that properly describe Hibernate Validator 7

It took me a long time. So I will note it.

In short:

  • If you use `javax.validation`, `javax.validation:validation-api:2.0.1.Final` is the latest version and the validator is implemented in `org.hibernate.validator:hibernate-validator:6.2.3.Final`.
  • If you use `jakarta.validation`, `jakarta.validation:jakarta.validation-api:3.0.0` is the latest version and the validator is implemented in `org.hibernate.validator:hibernate-validator:7.0.4.Final`.

It is understood that I don't know if I am wrong or not.

Since I'm using Gradle, I write in Gradle's syntax.

dependencies {
    // https://mvnrepository.com/artifact/javax.validation/validation-api
    implementation("javax.validation:validation-api:2.0.1.Final")

    testImplementation("org.junit.jupiter:junit-jupiter:5.8.2")
    // https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator
    testRuntimeOnly("org.hibernate.validator:hibernate-validator:6.2.3.Final")// OK
    // testRuntimeOnly("org.hibernate.validator:hibernate-validator:7.0.4.Final")// NG
    // https://mvnrepository.com/artifact/org.glassfish/javax.el
    testRuntimeOnly("org.glassfish:javax.el:3.0.0")
}

If you have a project with a dependency description like this, and you know that the latest version of Hibernate Validator is 7, you may want to write as follows:

testRuntimeOnly("org.hibernate.validator:hibernate-validator:7.0.4.Final")

But when you do that, it doesn't work.

There is a stack overflow question,
Unable to create a Configuration, because no Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath
https://stackoverflow.com/questions/36329001/unable-to-create-a-configuration-because-no-bean-validation-provider-could-be-f

The questioner asks, he/she configured as follows:

<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>7.0</version>
</dependency>

and got error:

javax.validation.ValidationException: Unable to create a Configuration, because no Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:271)
at org.springframework.validation.beanvalidation.LocalValidatorFactoryBean.afterPropertiesSet(LocalValidatorFactoryBean.java:223)
at org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean.afterPropertiesSet(OptionalValidatorFactoryBean.java:40)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:667)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:633)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:552)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:493)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
at javax.servlet.GenericServlet.init(GenericServlet.java:158)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1241)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1154)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1041)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4944)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5230)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

I met a similar problem and could not proceed. Actually,

javax.validation.ValidationException

is one of the points.

One of the respondents said

In my case, I moved to Hibernate 7.x but had an old explicit dependency on:

and recommends "removing" javax.validation:validation-api:2.0.1.

Another respondent said

I made it work downgrading the dependency of hibernate-validator from version 7.0.2.Final to 6.0.13.Final.

This is the point...


In common pages, if you want to use the @Size annotation, they suggest to declare import:

import javax.validation.constraints.Size;

, and it actually works.

Please look at
Hibernate Validator Migration Guide
https://hibernate.org/validator/documentation/migration-guide/
.

7.0.0.CR1
Jakarta EE 9 (a.k.a. the big jakarta.* package change)
...
See https://in.relation.to/2020/12/08/hibernate-validator-700-62-cr1-released/ for more details.

Let's see https://in.relation.to/2020/12/08/hibernate-validator-700-62-cr1-released/ .

Jakarta EE 9 is an iterative release on top of EE 8 with the main purpose of renaming all the javax. packages to the jakarta. packages.

The rest of the document should be read at your discretion. javax. is being old import.

A japanese document
Bean Validation 2.0 を Java SE のプログラムに導入する
https://qiita.com/niwasawa/items/7ab89140eb1b0c5b5eea
suggested to use 3 packages together:

  • javax.validation:validation-api (Bean Validation API)
  • org.hibernate.validator:hibernate-validator (Bean Validation API を実装したライブラリ)
  • org.glassfish:javax.el (Unified Expression Language を実装したライブラリ)

, or you may get errors like this:

javax.validation.NoProviderFoundException: Unable to create a Configuration, because no Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.

javax.validation.ValidationException: HV000183: Unable to initialize 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead

.

Java

Posted by tako