javax.validation.ValidationException:HV000183:无法加载'javax.el.E​​xpressionFactory'

gst*_*low 94 java validation hibernate hibernate-validator maven

我尝试使用hibernate验证器编写非常简单的应用程序:

我的步骤:

在pom.xml中添加以下依赖项:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.1.1.Final</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

写代码:

class Configuration {
    Range(min=1,max=100)
    int threadNumber;
    //...

    public static void main(String[] args) {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();

        Validator validator = factory.getValidator();

        Configuration configuration = new Configuration();
        configuration.threadNumber = 12;
            //...

        Set<ConstraintViolation<Configuration>> constraintViolations = validator.validate(configuration);
        System.out.println(constraintViolations);

    }
}
Run Code Online (Sandbox Code Playgroud)

我得到以下stacktrace:

Exception in thread "main" javax.validation.ValidationException: Unable to instantiate Configuration.
    at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:279)
    at javax.validation.Validation.buildDefaultValidatorFactory(Validation.java:110)
    ...
    at org.hibernate.validator.internal.engine.ConfigurationImpl.<init>(ConfigurationImpl.java:110)
    at org.hibernate.validator.internal.engine.ConfigurationImpl.<init>(ConfigurationImpl.java:86)
    at org.hibernate.validator.HibernateValidator.createGenericConfiguration(HibernateValidator.java:41)
    at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:276)
    ... 2 more
Run Code Online (Sandbox Code Playgroud)

我错了什么?

gst*_*low 149

添加到pom.xml以下依赖项后它正在工作:

<dependency>
   <groupId>javax.el</groupId>
   <artifactId>javax.el-api</artifactId>
   <version>2.2.4</version>
</dependency>
<dependency>
   <groupId>org.glassfish.web</groupId>
   <artifactId>javax.el</artifactId>
   <version>2.2.4</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

Hibernate Validator入门

  • `<dependency> <groupId> javax.el </ groupId> <artifactId> javax.el-api </ artifactId> <version> 2.3.1 </ version> </ dependency>`对我来说已足够 (8认同)
  • Bean Validation 1.1需要表达式依赖于类路径.另见http://hibernate.org/validator/documentation/getting-started/ (5认同)
  • 看起来他们推荐SE环境的github页面:https://github.com/hibernate/hibernate-validator.最重要的是对我来说足够了. (3认同)

Bru*_*uno 56

做的

<dependency>
   <groupId>javax.el</groupId>
   <artifactId>javax.el-api</artifactId>
   <version>2.2.4</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

  • 为什么`hibernate-validator`不依赖于依赖? (5认同)
  • 它实际上在 pom 文件中标记为依赖项,但提供了 Maven 范围。这意味着如果您的 JavaEE 服务器没有为您提供,您有责任自己添加它。 (2认同)

wal*_*ros 15

如果您使用tomcat作为服务器运行时并且在测试中遇到此错误(因为测试期间tomcat运行时不可用),那么包含tomcat el运行时而不是glassfish中的运行时是有意义的.这将是:

    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-el-api</artifactId>
        <version>8.5.14</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-jasper-el</artifactId>
        <version>8.5.14</version>
        <scope>test</scope>
    </dependency>
Run Code Online (Sandbox Code Playgroud)


her*_*rau 11

关于Hibernate验证器文档页面,您必须定义对JSR-341实现的依赖关系:

<dependency>
   <groupId>org.glassfish</groupId>
   <artifactId>javax.el</artifactId>
   <version>3.0.1-b11</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)


Bas*_*que 11

雅加达命名空间

作为从OracleEclipse 基金会移交的一部分,Java EE将更名为Jakarta EE。在 Jakarta EE 9 中,Java 包名称从 更改javax.*jakarta.*.

M. Justin对于雅加达的回答是正确的。我添加这个答案是为了提供更多解释和具体示例。

接口与实现

Jakarta Validation(以前称为Jakarta Bean Validation)是 Java 中 API 的规范。此规范的二进制库仅包含接口,而不包含可执行代码。所以我们还需要这些接口的实现。

我只知道Jakarta Validation版本 2 和 3 规范的一种实现:Hibernate Validator版本 6 和 7(分别)。

桌面和控制台应用程序

对于 Web 应用程序,符合 Jakarta 标准的 Web 容器将提供执行 Bean 验证所需的接口和实现。

对于桌面和控制台应用程序,我们没有这样的符合 Jakarta 标准的 Web 容器。因此,您必须将接口jar和实现 jar 与您的应用程序捆绑在一起。

您可以使用MavenGradleIvy等依赖管理工具来下载并捆绑接口和实现 jar。

雅加达表达语言

要运行Jakarta Bean Validation,我们还需要另一个 Jakarta 工具:Jakarta Expression Language,一种用于嵌入和评估表达式的专用编程语言雅加达表达式语言也简称为EL

Jakarta 表达式语言由 Jakarta EE 定义为一种规范,您必须下载一个 jar 接口。并且您还需要在另一个 jar 中获取这些接口的实现。

您可以选择多种实现。截至 2021 年 3 月,我知道Eclipse Foundation 提供了Eclipse Glassfish作为独立库的实现,我们可以免费下载。可能还有其他实现,例如IBM Corporation 的Open Liberty 。货比三家,寻找适合您需求的实施方案。

Maven POM 依赖项

将所有这些信息放在一起,您需要四个 jar: Jakarta ValidationJakarta Expression Language两个项目各一对接口和实现 jar 。

  • 雅加达验证
    • 界面
    • 执行
  • 雅加达表达语言
    • 界面
    • 执行

如果 Maven 是您选择的工具,那么以下是您需要添加到 Maven POM 文件中的四个依赖项。

如上所述,您也许可以找到另一种 EL 实现来替代我在这里使用的 Glassfish 库。

<!--********| Jakarta Validation  |********-->

<!-- Interface -->

<!-- https://mvnrepository.com/artifact/jakarta.validation/jakarta.validation-api -->
<dependency>
    <groupId>jakarta.validation</groupId>
    <artifactId>jakarta.validation-api</artifactId>
    <version>3.0.0</version>
</dependency>

<!-- Implementation -->

<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>7.0.1.Final</version>
</dependency>

<!-- Jakarta Expression Language -->

<!-- Interface -->

<!-- https://mvnrepository.com/artifact/jakarta.el/jakarta.el-api -->
<dependency>
    <groupId>jakarta.el</groupId>
    <artifactId>jakarta.el-api</artifactId>
    <version>4.0.0</version>
</dependency>

<!-- Implementation -->

<!-- https://mvnrepository.com/artifact/org.glassfish/jakarta.el -->
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>jakarta.el</artifactId>
    <version>4.0.1</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

这应该消除javax.validation.ValidationException: HV000183: Unable to load 'javax.el.ExpressionFactory'错误。

用法示例

您可以使用以下简单的类来测试您的设置Car。我们对三个成员字段中的每一个都进行了验证。

package work.basil.example.beanval;

import jakarta.validation.constraints.*;

public class Car
{
    // ---------------|  Member fields  |----------------------------
    @NotNull
    private String manufacturer;

    @NotNull
    @Size ( min = 2, max = 14 )
    private String licensePlate;

    @Min ( 2 )
    private int seatCount;

    // ---------------|  Constructors  |----------------------------
    public Car ( String manufacturer , String licensePlate , int seatCount )
    {
        this.manufacturer = manufacturer;
        this.licensePlate = licensePlate;
        this.seatCount = seatCount;
    }

    // ---------------|  Object overrides  |----------------------------

    @Override
    public String toString ( )
    {
        return "Car{ " +
                "manufacturer='" + manufacturer + '\'' +
                " | licensePlate='" + licensePlate + '\'' +
                " | seatCount=" + seatCount +
                " }";
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,如果使用 Java 16 及更高版本,请改用更简短的内容record

package work.basil.example.beanval;

import jakarta.validation.constraints.*;

public record Car (
        @NotNull
        String manufacturer ,
        @NotNull
        @Size ( min = 2, max = 14 )
        String licensePlate ,
        @Min ( 2 )
        int seatCount
)
{
}
Run Code Online (Sandbox Code Playgroud)

运行验证。首先我们运行一个成功配置的Car对象。然后我们实例化第二个Car有缺陷的对象,违反了三个字段中每一个字段的一个约束。

package work.basil.example.beanval;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;

import java.util.Set;

public class App
{
    public static void main ( String[] args )
    {
        App app = new App();
        app.demo();
    }

    private void demo ( )
    {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();

        // No violations.
        {
            Car car = new Car( "Honda" , "ABC-789" , 4 );
            System.out.println( "car = " + car );

            Set < ConstraintViolation < Car > > violations = validator.validate( car );
            System.out.format( "INFO - Found %d violations.\n" , violations.size() );
        }

        // 3 violations.
        {
            Car car = new Car( null , "X" , 1 );
            System.out.println( "car = " + car );

            Set < ConstraintViolation < Car > > violations = validator.validate( car );
            System.out.format( "INFO - Found %d violations.\n" , violations.size() );
            violations.forEach( carConstraintViolation -> System.out.println( carConstraintViolation.getMessage() ) );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

运行时。

car = Car{ manufacturer='Honda' | licensePlate='ABC-789' | seatCount=4 }
INFO - Found 0 violations.
car = Car{ manufacturer='null' | licensePlate='X' | seatCount=1 }
INFO - Found 3 violations.
must be greater than or equal to 2
must not be null
size must be between 2 and 14
Run Code Online (Sandbox Code Playgroud)


Mic*_*mal 9

如果您将Spring Boot与启动程序一起使用-此依赖项会同时添加tomcat-embed-elhibernate-validator依赖项:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Run Code Online (Sandbox Code Playgroud)


Mar*_*lte 6

如果你不需要javax.el(例如在JavaSE的应用程序),使用ParameterMessageInterpolatorHibernate的验证。Hibernate验证器是一个独立的组件,无需Hibernate本身即可使用。

依赖于休眠验证器

<dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-validator</artifactId>
   <version>6.0.16.Final</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

使用ParameterMessageInterpolator

import javax.validation.Validation;
import javax.validation.Validator;
import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator;

private static final Validator VALIDATOR =
  Validation.byDefaultProvider()
    .configure()
    .messageInterpolator(new ParameterMessageInterpolator())
    .buildValidatorFactory()
    .getValidator();
Run Code Online (Sandbox Code Playgroud)

  • 这应该是选择的答案。 (3认同)
  • 是的,我不想添加更多的依赖。好工作 (2认同)

M. *_*tin 6

Hibernate Validator 需要——但不包括——表达式语言 (EL)实现。添加对一个的依赖将解决这个问题。

<dependency>
   <groupId>org.glassfish</groupId>
   <artifactId>jakarta.el</artifactId>
   <version>3.0.3</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

此要求记录在Hibernate Validator 入门文档中。在 Java EE 环境中,它将由容器提供。在像您这样的独立应用程序中,需要提供它。

Hibernate Validator 还需要统一表达式语言 ( JSR 341 ) 的实现来评估约束违反消息中的动态表达式。

当您的应用程序在 Java EE 容器(例如WildFly )中运行时,容器已经提供了 EL 实现。

但是,在 Java SE 环境中,您必须将实现作为依赖项添加到 POM 文件中。例如,您可以添加以下依赖项以使用 JSR 341 参考实现:

<dependency>
  <groupId>org.glassfish</groupId>
  <artifactId>jakarta.el</artifactId>
  <version>${version.jakarta.el-api}</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

表达式语言实现

存在几种 EL 实现。一种是文档中提到的 Jakarta EE Glassfish参考实现。另一个是嵌入式Tomcat,当前版本的Spring Boot默认使用它。该版本的 EL 可以按如下方式使用:

<dependency>
   <groupId>org.apache.tomcat.embed</groupId>
   <artifactId>tomcat-embed-el</artifactId>
   <version>9.0.48</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

本评论中所述,必须选择表达式语言的兼容版本。Glassfish 实现被指定为Hibernate Validator提供的-scope 依赖项,因此那里指定的版本应该可以正常工作。特别是,Hibernate Validator 7使用 Glassfish EL 实现的第 4 版,而Hibernate 6使用第 3 版。

弹簧靴

在 Spring Boot 项目中,spring-boot-starter-validation通常会使用依赖项,而不是直接指定 Hibernate 验证器和 EL 库。该依赖项包括org.hibernate.validator:hibernate-validatortomcat-embed-el

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
    <version>2.4.3.RELEASE</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

  • 注意版本兼容性:我刚刚发现 Hibernate Validator 6.1 无法与 `org.glassfish:jakarta.el:4.0.1` 一起使用,我需要坚持使用 `org.glassfish:jakarta.el:3.0.3` (直到我猜我升级了 Hibernate Validator)。 (2认同)