Jakarta namespace
As part of the handover from Oracle to the Eclipse Foundation, Java EE is being renamed to Jakarta EE. With Jakarta EE 9, the Java package names were changed from javax.*
to jakarta.*
.
The Answer by M. Justin is correct with regard to Jakarta. I added this Answer to provide more explanation and specific examples.
Interface versus Implementation
Jakarta Bean Validation is a specification of an API in Java. The binary library for this spec contains only interfaces, not executable code. So we also need an implementation of these interfaces.
I know of only one implementation of Jakarta Bean Validation versions 2 & 3 specifications: Hibernate Validator versions 6 and 7 (respectively).
Desktop & console apps
For web apps, a Jakarta-compliant web container will provide both the interface and the implementation needed to perform Bean Validation.
For desktop and console apps, we have no such Jakarta-compliant web container. So you must bundle both the interface jar and the implementation jar with your app.
You can use a dependency-management tool such as Maven, Gradle, or Ivy to download and bundle the interface & implementation jars.
Jakarta Expression Language
To run Jakarta Bean Validation, we need another Jakarta tool as well: Jakarta Expression Language, a special purpose programming language for embedding and evaluating expressions. Jakarta Expression Language is also known simply as EL.
Jakarta Expression Language is defined by Jakarta EE as a specification for which you must download a jar of interfaces. And you also need to obtain an implementation of these interfaces in another jar.
You may have choice of implementations. As of 2021-03, I know of Eclipse Glassfish by Eclipse Foundation providing an implementation as a separate library we can download free-of-cost. There may be other implementations, such as Open Liberty by IBM Corporation. Shop around for an implementation that suits your needs.
Maven POM dependencies
Pulling all this info together, you need four jars: A pair of interface and implementation jars for each of two projects, Jakarta Bean Validation and Jakarta Expression Language.
- Jakarta Bean Validation
- Jakarta Expression Language
The following are the four dependencies you need to add to your Maven POM file, if Maven is your tool of choice.
As mentioned above, you may be able to find another implementation of EL to substitute for the Glassfish library I use here.
<!--********| 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>
That should eliminate the javax.validation.ValidationException: HV000183: Unable to load 'javax.el.ExpressionFactory'
error.
Example usage
You can test your setup with the following simple class, Car
. We have validations on each of the three member fields.
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 +
" }";
}
}
Or, if using Java 16 and later, use a more brief record
instead.
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 the validation. First we run with a successfully configured Car
object. Then we instantiate a second Car
object that is faulty, violating one constraint on each of the three fields.
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() ) );
}
}
}
When run.
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