异常: HV000183: 无法加载‘ javax.el. ExpressionFactory’

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

我的脚步声:

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

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.1.Final</version>
</dependency>

编写代码:

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);


}
}

然后我得到了堆栈跟踪:

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

我做错了什么?

144295 次浏览

它在向 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>

开始使用 Hibernate Validator :

Hibernate 验证器还需要一个统一表达式语言(JSR 341)的实现来计算违反约束消息中的动态表达式。当应用程序在 JavaEE 容器(如 野蝇)中运行时,容器已经提供了 EL 实现。但是,在 JavaSE 环境中,必须将实现作为依赖项添加到 POM 文件中。例如,您可以添加以下两个依赖项来使用 JSR 341 参考实现:

<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>

只要

<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>

如果您使用 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>

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

<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.1-b11</version>
</dependency>

等级:

compile 'javax.el:javax.el-api:2.2.4'

如果您使用启动程序的春季启动-这个依赖项增加了 tomcat-embed-elhibernate-validator的依赖项:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

如果使用 SpringBoot,这个工作很好。即使使用 SpringReactiveMongo。

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

和验证配置:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.mapping.event.ValidatingMongoEventListener;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;


@Configuration
public class MongoValidationConfig {


@Bean
public ValidatingMongoEventListener validatingMongoEventListener() {
return new ValidatingMongoEventListener(validator());
}


@Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
}

如果您不需要 Javax.el(例如在 JavaSE 应用程序中) ,可以使用 Hibernate 验证器中的 内插器。 Hibernate 验证器是一个独立的组件,可以在不使用 冬眠本身的情况下使用。

依赖于 hibernate-validator

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.16.Final</version>
</dependency>

使用 Parameter terMessageInterpolator

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();

对于 sbt,使用以下版本

val glassfishEl = "org.glassfish" % "javax.el" % "3.0.1-b09"


val hibernateValidator = "org.hibernate.validator" % "hibernate-validator" % "6.0.17.Final"


val hibernateValidatorCdi = "org.hibernate.validator" % "hibernate-validator-cdi" % "6.0.17.Final"


Hibernate 验证器需要(但不包括) 表达式语言(EL)实现。在其中一个上添加依赖项将解决这个问题。

<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>3.0.3</version>
</dependency>

这个需求在 开始使用 Hibernate Validator文档中有记录。在 JavaEE 环境中,它将由容器提供。像你这样的绿色软体需要有人提供。

Hibernate 验证器还需要一个统一表达式语言(JSR 341)的实现来计算违反约束消息中的动态表达式。

当应用程序在 JavaEE 容器(如 野蝇)中运行时,容器已经提供了 EL 实现。

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

<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>${version.jakarta.el-api}</version>
</dependency>

表达式语言实现

有几个 EL 实现。一个是文档中提到的 JakartaEE玻璃鱼参考实现。另一个是嵌入式 雄猫,当前版本的 弹簧靴默认使用它。该版本的 EL 可以使用如下:

<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>9.0.48</version>
</dependency>

正如在 此评论中指出的,必须选择表达式语言的兼容版本。Glassfish 实现被指定为 Hibernate Validator 的 提供-scope 依赖项,因此指定的版本应该可以正常工作。特别是,Hibernate Validator 7使用 Glassfish EL 实现的版本4,而 休眠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>

我遇到了同样的问题,以上的答案没有帮助。我需要调试和找到它。

 <dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.6.0-cdh5.13.1</version>
<exclusions>
<exclusion>
<artifactId>jsp-api</artifactId>
<groupId>javax.servlet.jsp</groupId>
</exclusion>
</exclusions>
</dependency>

在排除了 jsp-api 之后,它对我起作用了。

雅加达名称空间

作为从 神使Eclipse基金会移交的一部分,Java EE被重命名为 雅加达 EE。对于 JakartaEE9,Java 包名称从 javax.*更改为 jakarta.*

关于雅加达,贾斯汀的回答是正确的。我添加这个答案是为了提供更多的解释和具体的例子。

接口与实现

JakartaBean 验证 是 Java 中 API 的规范。此规范的二进制库只包含 接口,而不包含可执行代码。因此,我们还需要这些接口的实现。

我只知道 JakartaBean 验证版本2和3规范的一个实现: < em > Hibernate Validator 版本6和7(分别)。

桌面和控制台应用程序

对于 Web 应用程序来说,一个雅加达兼容的 Web 容器将提供执行 Bean 验证所需的接口和实现。

对于桌面和控制台应用程序,我们没有这样的雅加达兼容的 Web 容器。因此,必须将接口 罐子和实现 jar 与应用程序捆绑在一起。

您可以使用依赖项管理工具(如 玛文< em > Gradle 艾薇)来下载和捆绑接口和实现 jar。

雅加达表达语言

要运行 JakartaBean 验证,我们还需要另一个 Jakartatool: < em > 雅加达表达语言 ,一个用于嵌入和计算 表情专用程序设计语言雅加达表达语言也简称为 EL

JakartaExpressionLanguage 由 JakartaEE 定义为一种规范,您必须为其下载一个 jar 接口。您还需要在另一个 jar 中获得这些接口的实现。

您可以选择实现。截至2021-03年度,我知道 月食玻璃鱼的 Eclipse基金会是提供一个独立的图书馆实现,我们可以免费下载。可能还有其他的实现,比如 IBM 公司的 开放自由。四处寻找适合您需要的实现。

Maven POM 依赖项

将所有这些信息放在一起,您需要四个 jar: 一对用于两个项目 JakartaBean 验证雅加达表达语言的接口和实现 jar。

  • JakartaBean 验证
    • 接口
    • 实施
  • 雅加达表达语言
    • 接口
    • 实施

以下是需要添加到 MavenPOM 文件中的四个依赖项(如果选择 Maven 的话)。

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

<!--********| Jakarta Bean 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>

这应该可以消除 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 +
" }";
}
}

或者,如果使用 Java16或更高版本,则使用更简短的 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
)
{
}

运行验证。首先,我们运行一个成功配置的 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() ) );
}
}
}

跑步的时候。

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

对于任何使用 Hibernate Validator 7(org.Hibernate.Validator: Hibernate-Validator: 7.0.0. Final)作为 JakartaBean 验证3.0实现的人来说,应该使用依赖项:

<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>4.0.0</version>
</dependency>

Hibernate Validator 文档所述

我被旧技术束缚住了,所以我必须补充以下内容:

    <dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>

其他答案报告相同的依赖项,我只更新了版本。