← Back to list

Java Bean Validation with Javax/Jakarta Validation

Validating data is very important in all projects. For this, Java has Bean Validation, which is a Java EE standard that allows us to…

Taner Şahin · 2023-12-26 00:14 · 36 claps · 5.1 min read
#java #validation #javax #bean-validation
Open on Medium ↗
Wiki topics: 💑 · Relationships

Java Bean Validation with Javax/Jakarta Validation

Validating data is very important in all projects. For this, Java has Bean Validation, which is a Java EE standard that allows us to validate. With the help of default annotations or custom validations, we can put constraints on the data and validate it. We will discuss some examples of how to use this validation and what we can do with it.

Photo by Clément Hélardot on Unsplash

Photo by Clément Hélardot on Unsplash

Adding Dependency

</dependencies>  
  <dependency>
   <groupId>jakarta.validation</groupId>
   <artifactId>jakarta.validation-api</artifactId>
   <version>2.0.2</version>
  </dependency>
</dependencies>

Jakarta EE now uses the Jakarta Validation API instead of javax.validation. This API, formerly known as javax.validation and provided under Java EE standards, is no longer part of Java EE and has continued its development under Jakarta EE.

There may be differences in the nomenclature in imports according to the version used.

You can find detailed information for the current version from the link. https://mvnrepository.com/artifact/jakarta.validation/jakarta.validation-api

Constraint Annotations

  • @AssertFalse: Validates that the value must be false.
  • @AssertTrue: Validates that the value must be true.
  • @DecimalMax: Specifies that the field must be a number less than or equal to the specified maximum.
  • @DecimalMin: Specifies that the field must be a number greater than or equal to the specified minimum.
  • @Digits: Specifies the exact number of integral and fractional digits for a number.
  • @Email: Validates that the value is a valid email address.
  • @Future: Specifies that the field must be a future date.
  • @FutureOrPresent: Specifies that the field must be a future or present date.
  • @Max: Validates that the value must be less than or equal to the specified maximum.
  • @Min: Validates that the value must be greater than or equal to the specified minimum.
  • @Negative: Validates that the value must be negative.
  • @NegativeOrZero: Validates that the value must be negative or zero.
  • @NotBlank: Ensures that the value is not null, empty, or whitespace.
  • @NotEmpty: Ensures that the value is not null or empty.
  • @NotNull: If applied to a field, asserts that the value must not be null.
  • @Null: If applied to a field, asserts that the value must be null.
  • @Past: Validates that the value must be in the past.
  • @PastOrPresent: Validates that the value must be in the past or present.
  • @Pattern: Validates that the value matches a regular expression pattern.
  • @Positive: Validates that the value must be positive.
  • @PositiveOrZero: Validates that the value must be positive or zero.
  • @Size: Validates that the value must be within the specified size range.
import javax.validation.constraints.*;

public class Example {
    @AssertFalse
    private boolean isInvalid;
    @AssertTrue
    private boolean isValid;
    @DecimalMax(value = "1000.00")
    private double maxAmount;
    @DecimalMin(value = "10.50")
    private double minAmount;
    @Digits(integer = 5, fraction = 2)
    private BigDecimal preciseNumber;
    @Email
    private String emailField;
    @Future
    private Date futureDate;
    @FutureOrPresent
    private LocalDateTime futureOrPresentDateTime;
    @Max(100)
    private int maxLimit;
    @Min(18)
    private int minAge;
    @Negative
    private int negativeValue;
    @NegativeOrZero
    private int zeroOrNegativeValue;
    @NotBlank
    private String notBlankField;
    @NotEmpty
    private String notEmptyField;
    @NotNull
    private String notNullField;
    @Null
    private String nullField;
    @Past
    private Date pastDate;
    @PastOrPresent
    private LocalDateTime pastOrPresentDateTime;
    @Pattern(regexp = "\\d{3}-\\d{2}-\\d{4}")
    private String patternField;
    @Positive
    private int positiveValue;
    @PositiveOrZero
    private int zeroOrPositiveValue;
    @Size(min = 2, max = 50)
    private String sizedValue;
}

In all constraints you can write the message for the validation with the message parameter.

import javax.validation.constraints.*;

public class Example {
    @Positive(message = "The value must be positive.')
    private int positiveValue;
}

Validation Using More Than One Field

With AssertTrue, we can control a certain logici by returning true or false using different fields.

import javax.validation.constraints.*;

public class Example {
    @Positive(message = "Principal amount must be positive.')
    private BigDecimal principalAmount;
    private BigDecimal totalDebt;

    // getters and setters

    @AssertTrue()
    private boolean isPrincipalAmountLessThanTotalDebt(){
      if(getPrincipalAmount != null && getTotalDebt() != null){
        return getTotalDebt().compareTo(getPrincipalAmount()) > 0;
      }
      return false;
    }
}

Custom Annotation

If the default annotations do not meet your needs, you can run all the logic you want by writing a custom annotation.

ElementType

java.lang.annotation.ElementType is an enumeration class used in the Java language. This class contains constants used to determine where annotations can be applied.

  • TYPE: Applicable to class, interface, or enum declaration.
  • FIELD: Applicable to a field (includes enum constants).
  • METHOD: Applicable to a method declaration.
  • PARAMETER: Applicable to formal parameter declaration.
  • CONSTRUCTOR: Applicable to a constructor declaration.
  • LOCAL_VARIABLE: Applicable to a local variable declaration.
  • PACKAGE: Applicable to a package declaration.

Retention

java.lang.annotation.RetentionPolicy is an enumeration class in Java that determines the visibility and availability of an annotation during different stages of a Java program's lifecycle.

  • SOURCE: Annotations are visible only in the source code and are discarded during the compilation process. They do not appear in the compiled bytecode and are primarily used by development tools and static code analysis.
  • CLASS: Annotations are retained in the class file but are not accessible at runtime. These annotations can be processed by compiler tools and other source code analysis tools but are not available for reflection or access during the program’s execution.
  • RUNTIME: Annotations are retained in the class file and are accessible at runtime through reflection. These annotations can be read and used by the Java Reflection API during program execution, providing valuable metadata information.

Example:

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
@Constraint(validatedBy = PaymentDateValidationImpl.class)
public @interface PaymentDateValidation {
    String message() default "The payment date must be at most 60 days from today.";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class PaymentDateValidationImpl implements ConstraintValidator<PaymentDateValidation, Date> {
    @Override
    public void initialize(CustomValidation constraintAnnotation) {
        // Initialization logic if needed
    }

    @Override
    public boolean isValid(Date paymentDate, ConstraintValidatorContext context) {
        if(paymentDate != null){
          Date lastValidDate = DateUtil.addDayToDate(getCurrentDate(), 60);
          long diffDayCount = DateUtil.calcDiffDates(paymentDate, lastValidDate);
          return diffDayCount <= 60;
        }
        return true;
    }
}
import javax.validation.constraints.*;

public class Example {
    @PaymentDateValidation()
    private Date paymentDate;
}

Sending a Dynamic Value to the Message of a Custom Annotation

We are replacing the today value in the message in our interface with %s. So we can send a value to this message.

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target({TYPE,FIELD, PARAMETER, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = PaymentDateValidationImpl.class)
public @interface PaymentDateValidation {
    String message() default "The payment date must be at most 60 days from %s.";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class PaymentDateValidationImpl implements ConstraintValidator<PaymentDateValidation, Date> {

    @Override
    public boolean isValid(Date paymentDate, ConstraintValidatorContext context) {
        if(paymentDate != null){
          Date lastValidDate = DateUtil.addDayToDate(getCurrentDate(), 60);
          long diffDayCount = DateUtil.calcDiffDates(paymentDate, lastValidDate);

          String defaultErrorMessage = context.getDefaultConstraintMessageTemplate();
          String formattedErrorMessage = String.format(defaultErrorMessage, getCurrentDateString());

          context.disableDefaultConstraintViolation();
          context.buildConstraintViolationWithTemplate(formattedErrorMessage).addConstraintViolation();
          return diffDayCount <= 60;
        }
        return true;
    }
}

Validation with Annotation

  • @Valid Annotation: The annotation is commonly used within the Bean Validation API scope. It’s primarily employed to enable form validation or validation of model objects.
import javax.validation.*;

@RestController
public class UserController {

    ...

    @PostMapping("/users")
    public ResponseEntity<BaseResponse> createUser(@Valid @RequestBody User user) {
      // Validation of fields inside the User object
      // If the fields are not valid, error messages are returned
      // This validation takes place before processing continues
      // ...
    }
}
  • @Validated Annotation: This is often used to enable parameter validation or argument validation within methods or classes.
import org.springframework.validation.annotation.Validated;

@Service
@Validated
public class UserService {

    public void updateUserEmail(@NotBlank String userId, @Email String newEmail) {
        // Validation of parameters using validated
        // userId cannot be blank, and newEmail must be in email format
        // ...
    }
}

Programmatic Validation

import javax.validation.ConstraintValidation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

@RestController
public class UserController{

  ...

  private Validator getValidator(){
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    return factory.getValidator();
  }

  @PostMapping("path = "/users")
  public ResponseEntity<BaseResponse> createUser(@RequestBody User user){
    BaseResponse response = new BaseResponse();

    Set<ConstraintViolation<User>> violations = getValidator().validate(user);
    if(!violations.isEmpty()){
      List<String> errorMessages = violations.stream().map(ConstraintViolation::getMessage()).toList();
      // Here you can use the values taken from violations according to your needs.
      response.setErrorMessages(errorMessages);
      return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
    }
    ...
  }
}

메타데이터
post_id
5c11d9ebc409
slug
java-bean-validation-with-javax-validation-5c11d9ebc409
url
https://medium.com/@tanersahin/java-bean-validation-with-javax-validation-5c11d9ebc409
canonical_url
https://medium.com/@tanersahin/java-bean-validation-with-javax-validation-5c11d9ebc409
author_url
https://medium.com/@tanersahin
status
ok
fetched_at
2026-07-24 16:59:40