Close

Java Bean Validation - Using constraints on constructor and method return values

[Last Updated: Aug 25, 2021]

In the last tutorial, we saw how to validator method/constructor parameters. In this tutorial we will see how to validator method/constructor return values.

Example

Using constraints on method return values

We can validate method return value to make sure that all post condition are met after calling the method.

package com.logicbig.example;

import javax.validation.*;
import javax.validation.constraints.Size;
import javax.validation.executable.ExecutableValidator;
import java.beans.IntrospectionException;
import java.lang.reflect.Method;
import java.util.Set;

public class MethodReturnValidationExample {

    private static class TestBean {
        @Size(min = 5)
        public int[] findNumbers () {
            return new int[]{1, 2, 3};
        }
    }

    public static void main (String[] args) throws NoSuchMethodException, IntrospectionException {
        TestBean test = new TestBean();
        int[] testNumbers = test.findNumbers();

        Method method = TestBean.class.getDeclaredMethod("findNumbers");

        Validator validator = getValidator();
        ExecutableValidator executableValidator = validator.forExecutables();
        Set<ConstraintViolation<TestBean>> violations =
                            executableValidator.validateReturnValue(test,
                                                method, testNumbers);

        if (violations.size() > 0) {
            violations.stream().forEach(MethodReturnValidationExample::printError);
        } else {
            //proceed using Order object
        }
    }

    private static Validator getValidator(){
        Configuration<?> config = Validation.byDefaultProvider().configure();
        ValidatorFactory factory = config.buildValidatorFactory();
        Validator validator = factory.getValidator();
        factory.close();
        return validator;
    }

    private static void printError (
                        ConstraintViolation<TestBean> violation) {
        System.out.println(violation.getPropertyPath() + " " + violation.getMessage());
    }
}

Output

findNumbers.<return value> size must be between 5 and 2147483647


Using constraints on constructor return value.

Constructors don't return values like method do but they return a newly instantiated object. We can find out validation violation on new object to make sure that all post conditions are met after the object creation.

Following example creates a custom constraints 'ValidOrder' to validate the returned constructor value. The assumed requirement in this example is: the total order prices should be $50 or more.


package com.logicbig.example;

import javax.validation.*;
import javax.validation.executable.ExecutableValidator;
import java.lang.annotation.*;
import java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Set;

public class ConstructorReturnValidationExample {

    public static class Order {
        private final BigDecimal price;
        private final BigDecimal quantity;

        @ValidOrder
        public Order (BigDecimal price, BigDecimal quantity) {
            this.price = price;
            this.quantity = quantity;
        }

        public BigDecimal getPrice () {
            return price;
        }

        public BigDecimal getQuantity () {
            return quantity;
        }

        public BigDecimal getTotalPrice () {
            return (price != null && quantity != null ?
                    price.multiply(quantity) : BigDecimal.ZERO)
                    .setScale(2, RoundingMode.CEILING);
        }
    }

    public static void main (String[] args) throws NoSuchMethodException {
        Order order = new Order(new BigDecimal(4.5), new BigDecimal(10));
        Constructor<Order> constructor =
                            Order.class.getConstructor(BigDecimal.class, BigDecimal.class);

        Validator validator = getValidator();
        ExecutableValidator executableValidator = validator.forExecutables();
        Set<ConstraintViolation<Order>> constraintViolations =
                            executableValidator.validateConstructorReturnValue(constructor, order);

        if (constraintViolations.size() > 0) {
            constraintViolations.stream().forEach(
                                ConstructorReturnValidationExample::printError);
        } else {
            //proceed using order
            System.out.println(order);
        }
    }

    private static Validator getValidator(){
        Configuration<?> config = Validation.byDefaultProvider().configure();
        ValidatorFactory factory = config.buildValidatorFactory();
        Validator validator = factory.getValidator();
        factory.close();
        return validator;
    }

    private static void printError (
                        ConstraintViolation<Order> violation) {
        System.out.println(violation.getPropertyPath() + " " + violation.getMessage());
    }

    @Target({ElementType.CONSTRUCTOR, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = OrderValidator.class)
    @Documented
    public static @interface ValidOrder {
        String message () default "total price must be 50 or greater for online order. " +
                            "Found: ${validatedValue.totalPrice}";

        Class<?>[] groups () default {};

        Class<? extends Payload>[] payload () default {};
    }

    public static class OrderValidator implements ConstraintValidator<ValidOrder, Order> {
        @Override
        public void initialize (ValidOrder constraintAnnotation) {
        }

        @Override
        public boolean isValid (Order order, ConstraintValidatorContext context) {
            if (order.getPrice() == null || order.getQuantity() == null) {
                return false;
            }
            return order.getTotalPrice()
                        .compareTo(new BigDecimal(50)) >= 0;

        }
    }
}

Output

Order.<return value> total price must be 50 or greater for online order. Found: 45.00


Example Project

Dependencies and Technologies Used:

  • hibernate-validator 6.2.0.Final (Hibernate's Jakarta Bean Validation reference implementation)
     Version Compatibility: 5.0.0.Final - 6.2.0.Final Version List
    ×

    Version compatibilities of hibernate-validator with this example:

      groupId: org.hibernate
      artifactId: hibernate-validator
      Reference implementation for Bean Validation 1.1
    • 5.0.0.Final
    • 5.0.1.Final
    • 5.0.2.Final
    • 5.0.3.Final
    • 5.1.0.Final
    • 5.1.1.Final
    • 5.1.2.Final
    • 5.1.3.Final
    • 5.2.0.Final
    • 5.2.1.Final
    • 5.2.2.Final
    • 5.2.3.Final
    • 5.2.4.Final
    • 5.2.5.Final
    • 5.3.0.Final
    • 5.3.1.Final
    • 5.3.2.Final
    • 5.3.3.Final
    • 5.3.4.Final
    • 5.3.5.Final
    • 5.3.6.Final
    • 5.4.0.Final
    • 5.4.1.Final
    • 5.4.2.Final
    • 5.4.3.Final
    • groupId: org.hibernate.validator
      artifactId: hibernate-validator
      Reference implementation for Bean Validation 2.0
    • 6.0.0.Final
    • 6.0.1.Final
    • 6.0.2.Final
    • 6.0.3.Final
    • 6.0.4.Final
    • 6.0.5.Final
    • 6.0.6.Final
    • 6.0.7.Final
    • 6.0.8.Final
    • 6.0.9.Final
    • 6.0.10.Final
    • 6.0.11.Final
    • 6.0.12.Final
    • 6.0.13.Final
    • 6.0.14.Final
    • 6.0.15.Final
    • 6.0.16.Final
    • 6.0.17.Final
    • 6.0.18.Final
    • 6.0.19.Final
    • 6.0.20.Final
    • 6.0.21.Final
    • 6.0.22.Final
    • 6.1.0.Final
    • 6.1.1.Final
    • 6.1.2.Final
    • 6.1.3.Final
    • 6.1.4.Final
    • 6.1.5.Final
    • 6.1.6.Final
    • 6.1.7.Final
    • 6.2.0.Final
    • Version 7 and later:
      Jakarta Bean Validation 3.0
      jakarta.* packages

    Versions in green have been tested.

  • javax.el-api 3.0.0 (Expression Language 3.0 API)
  • javax.el 2.2.6 (Expression Language 2.2 Implementation)
  • JDK 8
  • Maven 3.8.1

Using constraints on constructor/method return values Select All Download
  • return-value-validation
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • MethodReturnValidationExample.java

    See Also