All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.terheyden.valid.ValidationsBuilder Maven / Gradle / Ivy

There is a newer version: 0.0.9
Show newest version
package com.terheyden.valid;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.validator.HibernateValidator;
import org.hibernate.validator.HibernateValidatorConfiguration;
import org.hibernate.validator.cfg.ConstraintMapping;
import org.hibernate.validator.cfg.context.ConstraintDefinitionContext;
import org.hibernate.validator.cfg.context.ConstraintDefinitionContext.ValidationCallable;

import javax.validation.ConstraintValidator;
import javax.validation.Validation;
import javax.validation.ValidatorFactory;

/**
 * Used to create dynamic relationships between validators and constraints.
 * Example usage:
 * 
 * {@code
 * ValidationsBuilder builder = new ValidationsBuilder();
 * builder.constraintMapping()
 *     .type(User.class)
 *     ...etc...
 * Validations.setValidator(builder);
 * }
 * 
*

* Note that, currently, you cannot add more than one constraint to an annotation. * For that, you'll have to do it long-form via {@link #constraintMapping()}. * * @see * * Programmatic API Reference * */ public class ValidationsBuilder { /** * In order to create a custom, dynamic, programmatic validator, * we switch over to the {@link HibernateValidator}. */ private final HibernateValidatorConfiguration configuration = Validation .byProvider(HibernateValidator.class) .configure(); /** * This one mapping object can have many constraints added to it. */ private final ConstraintMapping constraintMapping = configuration.createConstraintMapping(); /** * When utilizing the fluent builder, we need to group mappings by annotation type, * so this map is used to store the mappings. * * An annotation may either be mapped to a validation class (@link ConstraintMapToClass) * or a validation function (@link ConstraintMapToFunction). Both of those types extend * {@link ConstraintMapper}. */ private final Map> constraints = new HashMap<>(); /** * Programmatically add a validator to a constraint annotation. * * @param annotationClass the constraint annotation to associate with the validator * @param validatorClass the validator to associate with the constraint annotation * @see * * Hibernate Reference * */ public ValidationsBuilder addConstraintValidator( Class annotationClass, Class> validatorClass) { // A validation annotation may have multiple types associated with it // (for example, @NotEmpty works for Strings and Lists and each type needs its own validator). // We store those mappings and build them all at the end. constraints.computeIfAbsent( annotationClass, annClass -> new ArrayList<>() ).add(new ConstraintMapToClass<>(annotationClass, validatorClass)); return this; } /** * Add a validator to a constraint annotation as a lambda function. * * @param annotationClass the constraint annotation to associate with the validator * @param typeToValidate type of object to validate * @param validationFunction the validation function to use — true if valid, false if invalid * @see * * Hibernate Reference * */ public ValidationsBuilder addConstraintValidator( Class annotationClass, Class typeToValidate, ValidationCallable validationFunction) { // A validation annotation may have multiple types associated with it // (for example, @NotEmpty works for Strings and Lists and each type needs its own validator). // We store those mappings and build them all at the end. constraints.computeIfAbsent( annotationClass, annClass -> new ArrayList<>() ).add(new ConstraintMapToFunction<>(annotationClass, typeToValidate, validationFunction)); return this; } /** * Use this only if you need full control over the Hibernate Validator configuration. * For example: *

     * {@code
     * builder.constraintMapping()
     *    .type(User.class)
     *        .field("name")
     *        .constraint(new GenericConstraintDef<>(MyConstraint.class))
     *        .param("value", "ConfigValue")
     *        .valid()
     *    .type(Employee.class)
     *        .field("id")
     *        ...etc.
     * }
     * 
* * @see * * Programmatic API Reference * */ public ConstraintMapping constraintMapping() { return constraintMapping; } /** * Build the custom validation factory. */ /* package */ ValidatorFactory build() { // A validation annotation may only be defined ONCE in [constraintMapping]. // Here's an example of how to add two validators: // constraintMapping // .constraintDefinition(IsNull.class) // .validatedBy(IsNullValidator.class) // mapping 1 // .validateType(String.class) // mapping 2 // .with(str -> str == null) for (Class annotationClass : constraints.keySet()) { ConstraintDefinitionContext constraintCtx = constraintMapping.constraintDefinition(annotationClass); for (ConstraintMapper constraint : constraints.get(annotationClass)) { constraint.addConstraint(constraintCtx); } } return configuration.addMapping(constraintMapping).buildValidatorFactory(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy