@Test
  public void testCustomConstraintValidatorFactory() {

    Configuration<?> configuration = Validation.byDefaultProvider().configure();
    assertDefaultBuilderAndFactory(configuration);

    ValidatorFactory factory = configuration.buildValidatorFactory();
    Validator validator = factory.getValidator();

    Customer customer = new Customer();
    customer.setFirstName("John");

    Set<ConstraintViolation<Customer>> constraintViolations = validator.validate(customer);
    assertEquals(constraintViolations.size(), 1, "Wrong number of constraints");
    ConstraintViolation<Customer> constraintViolation = constraintViolations.iterator().next();
    assertEquals("may not be empty", constraintViolation.getMessage(), "Wrong message");

    // get a new factory using a custom configuration
    configuration = Validation.byDefaultProvider().configure();
    configuration.constraintValidatorFactory(
        new ConstraintValidatorFactory() {

          public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {
            if (key == NotNullValidator.class) {
              return (T) new BadlyBehavedNotNullConstraintValidator();
            }
            return new ConstraintValidatorFactoryImpl().getInstance(key);
          }
        });
    factory = configuration.buildValidatorFactory();
    validator = factory.getValidator();
    constraintViolations = validator.validate(customer);
    assertEquals(constraintViolations.size(), 0, "Wrong number of constraints");
  }
  public static ValidatorFactory createValidatorFactory(ValidatorProvider provider) {
    Configuration<?> config = Validation.byDefaultProvider().configure();

    config.constraintValidatorFactory(
        new CustomConstraintValidatorFactory(
            config.getDefaultConstraintValidatorFactory(), provider));

    return config.buildValidatorFactory();
  }
  @Override
  @SuppressWarnings("unchecked")
  public void afterPropertiesSet() {
    @SuppressWarnings("rawtypes")
    Configuration configuration =
        (this.providerClass != null
            ? Validation.byProvider(this.providerClass).configure()
            : Validation.byDefaultProvider().configure());

    MessageInterpolator targetInterpolator = this.messageInterpolator;
    if (targetInterpolator == null) {
      targetInterpolator = configuration.getDefaultMessageInterpolator();
    }
    configuration.messageInterpolator(new LocaleContextMessageInterpolator(targetInterpolator));

    if (this.traversableResolver != null) {
      configuration.traversableResolver(this.traversableResolver);
    }

    ConstraintValidatorFactory targetConstraintValidatorFactory = this.constraintValidatorFactory;
    if (targetConstraintValidatorFactory == null && this.applicationContext != null) {
      targetConstraintValidatorFactory =
          new SpringConstraintValidatorFactory(
              this.applicationContext.getAutowireCapableBeanFactory());
    }
    if (targetConstraintValidatorFactory != null) {
      configuration.constraintValidatorFactory(targetConstraintValidatorFactory);
    }

    configureParameterNameProviderIfPossible(configuration);

    if (this.mappingLocations != null) {
      for (Resource location : this.mappingLocations) {
        try {
          configuration.addMapping(location.getInputStream());
        } catch (IOException ex) {
          throw new IllegalStateException("Cannot read mapping resource: " + location);
        }
      }
    }

    for (Map.Entry<String, String> entry : this.validationPropertyMap.entrySet()) {
      configuration.addProperty(entry.getKey(), entry.getValue());
    }

    // Allow for custom post-processing before we actually build the ValidatorFactory.
    postProcessConfiguration(configuration);

    this.validatorFactory = configuration.buildValidatorFactory();
    setTargetValidator(this.validatorFactory.getValidator());
  }
 @Override
 public T constraintValidatorFactory(
     final ConstraintValidatorFactory constraintValidatorFactory) {
   return delegate.constraintValidatorFactory(constraintValidatorFactory);
 }
  @SuppressWarnings("unchecked")
  private static Configuration<?> getConfig(final ValidationInfo info) {
    Configuration<?> target = null;
    final Thread thread = Thread.currentThread();
    final ClassLoader classLoader = thread.getContextClassLoader();

    String providerClassName = info.providerClassName;
    if (providerClassName == null) {
      providerClassName =
          SystemInstance.get().getOptions().get(VALIDATION_PROVIDER_KEY, (String) null);
    }

    if (providerClassName != null) {
      try {
        @SuppressWarnings({"unchecked", "rawtypes"})
        final Class clazz = classLoader.loadClass(providerClassName);
        target = Validation.byProvider(clazz).configure();
        logger.info("Using " + providerClassName + " as validation provider.");
      } catch (final ClassNotFoundException e) {
        logger.warning("Unable to load provider class " + providerClassName, e);
      } catch (final ValidationException ve) {
        logger.warning(
            "Unable create validator factory with provider "
                + providerClassName
                + " ("
                + ve.getMessage()
                + ")."
                + " Default one will be used.");
      }
    }
    if (target == null) {
      // force to use container provider to ignore any conflicting configuration
      thread.setContextClassLoader(ValidatorBuilder.class.getClassLoader());
      target = Validation.byDefaultProvider().configure();
      thread.setContextClassLoader(classLoader);
    }

    final Set<ExecutableType> types = new HashSet<>();
    for (final String type : info.validatedTypes) {
      types.add(ExecutableType.valueOf(type));
    }

    final Map<String, String> props = new HashMap<>();
    for (final Map.Entry<Object, Object> entry : info.propertyTypes.entrySet()) {
      final PropertyType property = new PropertyType();
      property.setName((String) entry.getKey());
      property.setValue((String) entry.getValue());

      props.put(property.getName(), property.getValue());
      if (logger.isDebugEnabled()) {
        logger.debug(
            "Found property '" + property.getName() + "' with value '" + property.getValue());
      }
      target.addProperty(property.getName(), property.getValue());
    }

    final OpenEjbBootstrapConfig bootstrapConfig =
        new OpenEjbBootstrapConfig(
            providerClassName,
            info.constraintFactoryClass,
            info.messageInterpolatorClass,
            info.traversableResolverClass,
            info.parameterNameProviderClass,
            new HashSet<>(info.constraintMappings),
            info.executableValidationEnabled,
            types,
            props);
    final OpenEjbConfig config = new OpenEjbConfig(bootstrapConfig, target);

    target.ignoreXmlConfiguration();

    final String messageInterpolatorClass = info.messageInterpolatorClass;
    if (messageInterpolatorClass != null) {
      try {
        @SuppressWarnings("unchecked")
        final Class<MessageInterpolator> clazz =
            (Class<MessageInterpolator>) classLoader.loadClass(messageInterpolatorClass);
        target.messageInterpolator(newInstance(config, clazz));
      } catch (final Exception e) {
        logger.warning(
            "Unable to set " + messageInterpolatorClass + " as message interpolator.", e);
      }
      logger.info("Using " + messageInterpolatorClass + " as message interpolator.");
    }
    final String traversableResolverClass = info.traversableResolverClass;
    if (traversableResolverClass != null) {
      try {
        @SuppressWarnings("unchecked")
        final Class<TraversableResolver> clazz =
            (Class<TraversableResolver>) classLoader.loadClass(traversableResolverClass);
        target.traversableResolver(newInstance(config, clazz));
      } catch (final Exception e) {
        logger.warning(
            "Unable to set " + traversableResolverClass + " as traversable resolver.", e);
      }
      logger.info("Using " + traversableResolverClass + " as traversable resolver.");
    }
    final String constraintFactoryClass = info.constraintFactoryClass;
    if (constraintFactoryClass != null) {
      try {
        @SuppressWarnings("unchecked")
        final Class<ConstraintValidatorFactory> clazz =
            (Class<ConstraintValidatorFactory>) classLoader.loadClass(constraintFactoryClass);
        target.constraintValidatorFactory(newInstance(config, clazz));
      } catch (final Exception e) {
        logger.warning("Unable to set " + constraintFactoryClass + " as constraint factory.", e);
      }
      logger.info("Using " + constraintFactoryClass + " as constraint factory.");
    }
    for (final String mappingFileName : info.constraintMappings) {
      if (logger.isDebugEnabled()) {
        logger.debug("Opening input stream for " + mappingFileName);
      }
      final InputStream in = classLoader.getResourceAsStream(mappingFileName);
      if (in == null) {
        logger.warning(
            "Unable to open input stream for mapping file "
                + mappingFileName
                + ". It will be ignored");
      } else {
        target.addMapping(in);
      }
    }
    if (info.parameterNameProviderClass != null) {
      try {
        final Class<ParameterNameProvider> clazz =
            (Class<ParameterNameProvider>) classLoader.loadClass(info.parameterNameProviderClass);
        target.parameterNameProvider(newInstance(config, clazz));
      } catch (final Exception e) {
        logger.warning(
            "Unable to set " + info.parameterNameProviderClass + " as parameter name provider.", e);
      }
      logger.info("Using " + info.parameterNameProviderClass + " as parameter name provider.");
    }

    return config;
  }
 @SuppressWarnings("unchecked")
 @Override
 public T constraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory) {
   configuration = configuration.constraintValidatorFactory(constraintValidatorFactory);
   return (T) this;
 }