javax.validation.ValidationException: HV000183: невозможно загрузить "javax.el.ExpressionFactory"
Я пытаюсь написать очень простое приложение с валидатором гибернации:
мои шаги:
добавить следующую зависимость в 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
Что я не прав?
16 ответов
Работает после добавления в 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>
Делать только
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>
Если вам не нужен javax.el (например, в приложении JavaSE), используйте ParameterMessageInterpolator от Hibernate.
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();
Если вы используете 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>
Если вы используете весеннюю загрузку со стартерами - эта зависимость добавляет оба tomcat-embed-el
а также hibernate-validator
зависимости:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Что касается страницы документации валидатора Hibernate, вы должны определить зависимость от JSR-341
реализация:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.1-b08</version>
</dependency>
Согласно документации по началу работы с Hibernate Validator, необходимо предоставить реализацию языка выражений (EL). В среде Java EE он будет предоставляться контейнером. Однако в отдельном приложении, таком как ваше, его необходимо предоставить.
Для Hibernate Validator также требуется реализация Unified Expression Language (JSR 341) для оценки динамических выражений в сообщениях о нарушении ограничений.
Когда ваше приложение выполняется в контейнере Java EE, таком как WildFly, реализация EL уже предоставляется контейнером.
Однако в среде Java SE вы должны добавить реализацию как зависимость к вашему POM-файлу. Например, вы можете добавить следующую зависимость для использования эталонной реализации JSR 341:
<dependency> <groupId>org.glassfish</groupId> <artifactId>javax.el</artifactId> <version></version> </dependency>
Пример зависимости в документации немного устарел, так как в 2018 году язык выражений был переведен на проект Jakarta EE. Чтобы использовать версию языка выражений Jakarta EE, добавьте следующую зависимость Eclipse Glassfish EL:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>3.0.3</version>
</dependency>
Существуют и другие реализации EL, которые можно использовать, кроме Glassfish. Например, Spring Boot по умолчанию использует встроенный Tomcat. Эту версию EL можно использовать следующим образом:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>9.0.30</version>
</dependency>
Jakarta пространство имен
В рамках передачи из Oracle в Фонд Затмения , Java EE переименовывается в Джакарте EE . В Jakarta EE 9 имена пакетов Java были изменены с
Ответ М. Иустина правильно в отношении Джакарты. Я добавил этот ответ, чтобы дать больше объяснений и конкретных примеров.
Интерфейс против реализации
<em>Jakarta Bean Validation</em> - это спецификация API на Java. Бинарная библиотека для этой спецификации содержит только интерфейсы , а не исполняемый код. Так что нам также нужна реализация этих интерфейсов.
Я знаю только одну реализацию спецификаций Jakarta Bean Validation версий 2 и 3: <em>Hibernate Validator</em> версий 6 и 7 (соответственно).
Настольные и консольные приложения
Для веб-приложений совместимый с Джакартой веб-контейнер будет предоставлять как интерфейс, так и реализацию, необходимые для выполнения проверки компонентов.
Для настольных и консольных приложений у нас нет такого Jakarta-совместимого веб-контейнера. Таким образом, вы должны связать и интерфейса, и jar реализации с вашим приложением.
Вы можете использовать инструмент управления зависимостями, такой как <em>Maven</em>, <em>Gradle</em> или Ivy, для загрузки и объединения <em>jar-</em> файлов интерфейса и реализации.
Джакартский язык выражения
Чтобы запустить Jakarta Bean Validation , нам понадобится еще один инструмент Jakarta: <em>Jakarta Expression Language</em>, <em>язык</em> программирования специального назначения для встраивания и оценки выражений . Джакартский язык выражений также известен как EL .
Jakarta Expression Language определяется Jakarta EE как спецификация, для которой вы должны загрузить банку интерфейсов. И вам также необходимо получить реализацию этих интерфейсов в другом банке.
У вас может быть выбор реализаций. По состоянию на 2021-03 гг. Мне известно о Eclipse Glassfish от Eclipse Foundation, предоставляющей реализацию в виде отдельной библиотеки, которую мы можем скачать бесплатно. Могут быть и другие реализации, например Open Liberty от IBM Corporation. Присмотритесь к реализации, которая соответствует вашим потребностям.
Зависимости Maven POM
Собрав всю эту информацию, вам понадобится четыре jar-файла: пара jar-файлов интерфейса и реализации для каждого из двух проектов, Jakarta Bean Validation и Jakarta Expression Language .
- Проверка Jakarta Bean
- Интерфейс
- Выполнение
- Джакартский язык выражения
- Интерфейс
- Выполнение
Ниже приведены четыре зависимости, которые вам нужно добавить в свой файл Maven POM, если Maven является вашим предпочтительным инструментом.
Как упоминалось выше, вы можете найти другую реализацию EL вместо библиотеки Glassfish, которую я использую здесь.
<!-- Jakarta Bean Validation -->
<!-- Interface -->
<!-- https://search.maven.org/artifact/jakarta.validation/jakarta.validation-api/3.0.0/jar -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.0</version>
</dependency>
<!-- Implementation -->
<!-- https://search.maven.org/artifact/org.hibernate.validator/hibernate-validator/7.0.0.Final/jar -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.0.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>
Это должно устранить
Пример использования
Вы можете протестировать свою установку с помощью следующего простого класса. У нас есть проверки для каждого из трех полей-членов.
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 +
" }";
}
}
Или, если вы используете Java 16 и новее, используйте более короткий <tcodeid="4377449"></tcodeid="4377449"> вместо.
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
)
{
}
Запустите проверку. Сначала запускаем с успешно настроенным объектом. Затем мы создаем второй
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
При использовании Spring Boot это работает хорошо. Даже с Spring Reactive Mongo.
<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();
}
}
Я столкнулся с той же проблемой, и приведенные выше ответы не помогли. Мне нужно отладить и найти.
<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 у меня это сработало.
Для 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 Validator 7 (org.hibernate.validator:hibernate-validator:7.0.0.Final) в качестве реализации Jakarta Bean Validation 3.0, следует использовать зависимость:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>4.0.0</version>
</dependency>
как указано в документации Hibernate Validator
для тех, кто использует Hibernate Validator 8, вам нужно использовать
<dependency>
<groupId>org.glassfish.expressly</groupId>
<artifactId>expressly</artifactId>
<version>5.0.0</version>
</dependency>
Я застрял на старых технологиях, поэтому мне пришлось добавить следующее:
<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>
Другие ответы сообщают о тех же зависимостях, я только обновил версии.
Если ваш сервер - websphere, и вы использовалиspring-boot-starter-validation
, исключатьtomcat-embed-el
.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
</exclusion>
</exclusions>
</dependency>