validatorFactoryProducers = run( GetValidatorProviderFactoryFromServiceLoader.action() );
+ if ( validatorFactoryProducers.isEmpty() ) {
+ validatorFactory = Validation.buildDefaultValidatorFactory();
+ LOG.defaultValidatorUsage();
+ }
+ else {
+ ValidatorFactoryProducer producer = validatorFactoryProducers.get( 0 );
+ try {
+ validatorFactory = producer.getConfiguredValidatorFactory();
+ if ( validatorFactoryProducers.size() > 1 ) {
+ LOG.multipleValidatorFactoryProducers( producer.getClass() );
+ }
+ }
+ catch (Exception e) {
+ throw LOG.errorCreatingValidatorFactoryFromProducer( producer.getClass(), e );
+ }
+ }
+ }
+
+ public ValidatorFactory getValidatorFactory() {
+ return validatorFactory;
+ }
+
+ /**
+ * Runs the given privileged action, using a privileged block if required.
+ *
+ * NOTE: This must never be changed into a publicly available method to avoid execution of arbitrary
+ * privileged actions within HV's protection domain.
+ */
+ private static T run(PrivilegedAction action) {
+ return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run();
+ }
+}
diff --git a/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/ValidationAspect.aj b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/ValidationAspect.aj
new file mode 100644
index 0000000000..27c4e9a496
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/ValidationAspect.aj
@@ -0,0 +1,125 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+package org.hibernate.validator.aspectj.validation.internal;
+
+import java.util.Set;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import javax.validation.Validator;
+import javax.validation.executable.ExecutableValidator;
+
+import org.hibernate.validator.aspectj.validation.Validate;
+
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.reflect.ConstructorSignature;
+import org.aspectj.lang.reflect.MethodSignature;
+
+/**
+ * An aspect that contains all the pointcuts and validation advices for method/constructor
+ * validation. Uses {@link ServiceLoaderBasedValidatorFactoryProducer} to get an instance
+ * of {@link Validator}.
+ *
+ * @author Marko Bekhta
+ */
+@Aspect
+public aspect ValidationAspect {
+
+ private final ExecutableValidator executableValidator;
+
+ {
+ // initialize an executable validator from a loaded validator factory:
+ ServiceLoaderBasedValidatorFactoryProducer producer = new ServiceLoaderBasedValidatorFactoryProducer();
+ executableValidator = producer.getValidatorFactory().getValidator().forExecutables();
+ }
+
+ /**
+ * Defines a pointcut that looks for {@code @Validate} annotated elements. Used to build up advices.
+ *
+ * @param validate a reference to the annotation
+ */
+ pointcut annotationPointCutDefinition(Validate validate): @annotation(validate);
+
+ /**
+ * Defines a pointcut that looks for any method executions. Used to build up advices.
+ */
+ pointcut atMethodExecution(): execution(* *(..));
+
+ /**
+ * Defines a pointcut that looks for any constructor executions. Used to build up advices.
+ * @param jp a joint point of constructor execution
+ */
+ pointcut atConstructorExecution(): execution(*.new(..));
+
+ /**
+ * Defines an advice for validation of method parameters
+ */
+ before(Validate validate): annotationPointCutDefinition(validate) && atMethodExecution() {
+ Set> violations = executableValidator.validateParameters(
+ thisJoinPoint.getTarget(),
+ ( (MethodSignature) thisJoinPoint.getSignature() ).getMethod(),
+ thisJoinPoint.getArgs(),
+ validate.groups()
+ );
+
+ // if there are any violations - throw a ConstraintViolationException
+ if ( !violations.isEmpty() ) {
+ throw new ConstraintViolationException( violations );
+ }
+ }
+
+ /**
+ * Defines an advice for validation of method return value
+ */
+ after(Validate validate) returning(Object returnValue): annotationPointCutDefinition(validate) && atMethodExecution() {
+ Set> violations = executableValidator.validateReturnValue(
+ thisJoinPoint.getTarget(),
+ ( (MethodSignature) thisJoinPoint.getSignature() ).getMethod(),
+ returnValue,
+ validate.groups()
+ );
+
+ // if there are any violations - throw a ConstraintViolationException
+ if ( !violations.isEmpty() ) {
+ throw new ConstraintViolationException( violations );
+ }
+ }
+
+ /**
+ * Defines an advice for validation of constructor parameters
+ */
+ before(Validate validate): annotationPointCutDefinition(validate) && atConstructorExecution() {
+ Set> violations = executableValidator.validateConstructorParameters(
+ ( (ConstructorSignature) thisJoinPoint.getSignature() ).getConstructor(),
+ thisJoinPoint.getArgs(),
+ validate.groups()
+ );
+
+ // if there are any violations - throw a ConstraintViolationException
+ if ( !violations.isEmpty() ) {
+ throw new ConstraintViolationException( violations );
+ }
+ }
+
+
+ /**
+ * Defines an advice for validation of method return value
+ */
+ after(Validate validate): annotationPointCutDefinition(validate) && atConstructorExecution() {
+ Set> violations = executableValidator.validateConstructorReturnValue(
+ ( (ConstructorSignature) thisJoinPoint.getSignature() ).getConstructor(),
+ thisJoinPoint.getTarget(),
+ validate.groups()
+ );
+
+ // if there are any violations - throw a ConstraintViolationException
+ if ( !violations.isEmpty() ) {
+ throw new ConstraintViolationException( violations );
+ }
+ }
+
+}
diff --git a/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/package-info.java b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/package-info.java
new file mode 100644
index 0000000000..eab9d8818f
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/package-info.java
@@ -0,0 +1,10 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+/**
+ * This package is part of the private Hibernate Validator API.
+ */
+package org.hibernate.validator.aspectj.validation.internal;
diff --git a/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/Log.java b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/Log.java
new file mode 100644
index 0000000000..cc43bd0528
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/Log.java
@@ -0,0 +1,42 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+package org.hibernate.validator.aspectj.validation.internal.util.logging;
+
+import static org.jboss.logging.Logger.Level.INFO;
+
+import org.hibernate.validator.aspectj.validation.internal.util.logging.formatter.ClassObjectFormatter;
+import org.hibernate.validator.aspectj.validation.spi.ValidatorFactoryProducer;
+
+import org.jboss.logging.BasicLogger;
+import org.jboss.logging.annotations.Cause;
+import org.jboss.logging.annotations.FormatWith;
+import org.jboss.logging.annotations.LogMessage;
+import org.jboss.logging.annotations.Message;
+import org.jboss.logging.annotations.MessageLogger;
+
+/**
+ * The Hibernate Validator AspectJ Validation logger interface for JBoss Logging.
+ *
+ * New log messages must always use an incremented message id.
+ *
+ * @author Marko Bekhta
+ */
+@MessageLogger(projectCode = "HVAJV")
+public interface Log extends BasicLogger {
+
+ @LogMessage(level = INFO)
+ @Message(id = 1, value = "No ValidatorFactoryProducers were found. Using a default ValidatorFactory.")
+ void defaultValidatorUsage();
+
+ @LogMessage(level = INFO)
+ @Message(id = 2, value = "Multiple ValidatorFactoryProducers were found. Check your configuration. Using one of the found producers (%s).")
+ void multipleValidatorFactoryProducers(Class extends ValidatorFactoryProducer> aClass);
+
+ @Message(id = 3, value = "Unable to create ValidatorFactory using %1$s producer.")
+ IllegalStateException errorCreatingValidatorFactoryFromProducer(@FormatWith(ClassObjectFormatter.class) Class extends ValidatorFactoryProducer> aClass, @Cause Exception cause);
+
+}
diff --git a/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/LoggerFactory.java b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/LoggerFactory.java
new file mode 100644
index 0000000000..1daea104d5
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/LoggerFactory.java
@@ -0,0 +1,29 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+package org.hibernate.validator.aspectj.validation.internal.util.logging;
+
+import java.lang.invoke.MethodHandles.Lookup;
+
+import org.jboss.logging.Logger;
+
+/**
+ * @author Hardy Ferentschik
+ * @author Kevin Pollet <kevin.pollet@serli.com> (C) 2012 SERLI
+ * @author Sanne Grinovero
+ */
+public final class LoggerFactory {
+
+ public static Log make(final Lookup creationContext) {
+ final String className = creationContext.lookupClass().getName();
+ return Logger.getMessageLogger( Log.class, className );
+ }
+
+ // private constructor to avoid instantiation
+ private LoggerFactory() {
+ }
+}
+
diff --git a/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/formatter/ClassObjectFormatter.java b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/formatter/ClassObjectFormatter.java
new file mode 100644
index 0000000000..e7a4f475ab
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/formatter/ClassObjectFormatter.java
@@ -0,0 +1,26 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+package org.hibernate.validator.aspectj.validation.internal.util.logging.formatter;
+
+/**
+ * Used with JBoss Logging to display class names in log messages.
+ *
+ * @author Gunnar Morling
+ */
+public class ClassObjectFormatter {
+
+ private final String stringRepresentation;
+
+ public ClassObjectFormatter(Class> clazz) {
+ this.stringRepresentation = clazz.getName();
+ }
+
+ @Override
+ public String toString() {
+ return stringRepresentation;
+ }
+}
diff --git a/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/formatter/package-info.java b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/formatter/package-info.java
new file mode 100644
index 0000000000..c0d0054dfc
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/formatter/package-info.java
@@ -0,0 +1,12 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+/**
+ * Contains formatters used by the {@link org.hibernate.validator.aspectj.validation.internal.util.logging.Log}.
+ *
+ * This package is part of the private Hibernate Validator API.
+ */
+package org.hibernate.validator.aspectj.validation.internal.util.logging.formatter;
diff --git a/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/package-info.java b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/package-info.java
new file mode 100644
index 0000000000..acdf15b510
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/package-info.java
@@ -0,0 +1,11 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+/**
+ *
+ * This package is part of the private Hibernate Validator API.
+ */
+package org.hibernate.validator.aspectj.validation.internal.util.logging;
diff --git a/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/package-info.java b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/package-info.java
new file mode 100644
index 0000000000..704032b2dc
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/package-info.java
@@ -0,0 +1,10 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+/**
+ * This package is part of the private Hibernate Validator API.
+ */
+package org.hibernate.validator.aspectj.validation.internal.util;
diff --git a/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/privilegedactions/GetValidatorProviderFactoryFromServiceLoader.java b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/privilegedactions/GetValidatorProviderFactoryFromServiceLoader.java
new file mode 100644
index 0000000000..1279c43ba3
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/privilegedactions/GetValidatorProviderFactoryFromServiceLoader.java
@@ -0,0 +1,45 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+package org.hibernate.validator.aspectj.validation.internal.util.privilegedactions;
+
+import java.security.PrivilegedAction;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+import org.hibernate.validator.aspectj.validation.spi.ValidatorFactoryProducer;
+
+/**
+ * A privileged action that accesses {@link ServiceLoader} mechanism to lookup
+ * a list of {@link ValidatorFactoryProducer}.
+ *
+ * @author Marko Bekhta
+ */
+public class GetValidatorProviderFactoryFromServiceLoader implements PrivilegedAction> {
+
+ private GetValidatorProviderFactoryFromServiceLoader() {
+ }
+
+ public static GetValidatorProviderFactoryFromServiceLoader action() {
+ return new GetValidatorProviderFactoryFromServiceLoader();
+ }
+
+ @Override
+ public List run() {
+ return loadInstances( GetValidatorProviderFactoryFromServiceLoader.class.getClassLoader() );
+
+ }
+
+ private List loadInstances(ClassLoader classloader) {
+ ServiceLoader loader = ServiceLoader.load( ValidatorFactoryProducer.class, classloader );
+
+ Iterable iterable = () -> loader.iterator();
+ return StreamSupport.stream( iterable.spliterator(), false )
+ .collect( Collectors.toList() );
+ }
+}
diff --git a/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/privilegedactions/package-info.java b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/privilegedactions/package-info.java
new file mode 100644
index 0000000000..7c4a3c2771
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/privilegedactions/package-info.java
@@ -0,0 +1,12 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+/**
+ * Contains privileged actions that should run within security manager.
+ *
+ * This package is part of the private Hibernate Validator API.
+ */
+package org.hibernate.validator.aspectj.validation.internal.util.privilegedactions;
diff --git a/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/package-info.java b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/package-info.java
new file mode 100644
index 0000000000..c2e90234d4
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/package-info.java
@@ -0,0 +1,13 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+
+/**
+ * Contains {@link org.hibernate.validator.aspectj.validation.Validate} marker annotation to mark methods for validation.
+ *
+ * This package is part of the public Hibernate Validator API.
+ */
+package org.hibernate.validator.aspectj.validation;
diff --git a/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/spi/ValidatorFactoryProducer.java b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/spi/ValidatorFactoryProducer.java
new file mode 100644
index 0000000000..7bd64ac9d4
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/spi/ValidatorFactoryProducer.java
@@ -0,0 +1,25 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+package org.hibernate.validator.aspectj.validation.spi;
+
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+
+/**
+ * Interface that should be implemented by end users to provide configured
+ * {@link ValidatorFactory}.
+ *
+ * @author Marko Bekhta
+ */
+public interface ValidatorFactoryProducer {
+
+ /**
+ * @return configured {@link ValidatorFactory} that will be used to create
+ * {@link Validator} to perform executable validation.
+ */
+ ValidatorFactory getConfiguredValidatorFactory();
+}
diff --git a/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/spi/package-info.java b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/spi/package-info.java
new file mode 100644
index 0000000000..cae4636934
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/spi/package-info.java
@@ -0,0 +1,14 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+
+/**
+ * Contains an interface {@link org.hibernate.validator.aspectj.validation.spi.ValidatorFactoryProducer}
+ * that can be implemented by users to configure and build a {@link javax.validation.ValidatorFactory}.
+ *
+ * This package is part of the public Hibernate Validator API.
+ */
+package org.hibernate.validator.aspectj.validation.spi;
diff --git a/executable-validation/aspectj-validation/src/test/java/org/hibernate/validator/aspectj/validation/internal/AspectValidationTest.java b/executable-validation/aspectj-validation/src/test/java/org/hibernate/validator/aspectj/validation/internal/AspectValidationTest.java
new file mode 100644
index 0000000000..d50d7ed8c6
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/test/java/org/hibernate/validator/aspectj/validation/internal/AspectValidationTest.java
@@ -0,0 +1,95 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+package org.hibernate.validator.aspectj.validation.internal;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import javax.validation.ConstraintViolationException;
+import javax.validation.Valid;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+import org.hibernate.validator.aspectj.validation.Validate;
+
+import org.testng.annotations.Test;
+
+/**
+ * @author Marko Bekhta
+ */
+public class AspectValidationTest {
+
+ @Test
+ public void testValidationOfMethodParameters() throws Exception {
+ Foo foo = new Foo( "", 1 );
+ assertThatThrownBy( () -> foo.doNoting( null ) )
+ .isInstanceOf( ConstraintViolationException.class )
+ .hasMessageContaining( "must not be null" );
+ }
+
+ @Test
+ public void testValidationOnMethodReturnValue() throws Exception {
+ Foo foo = new Foo( null, 1 );
+ assertThatThrownBy( () -> foo.getString() )
+ .isInstanceOf( ConstraintViolationException.class )
+ .hasMessageContaining( "must not be null" );
+ }
+
+ @Test
+ public void testValidationOnConstructorParameters() throws Exception {
+ assertThatThrownBy( () -> new Foo( 1 ) )
+ .isInstanceOf( ConstraintViolationException.class )
+ .hasMessageContaining( "must be greater than or equal to 10" );
+ }
+
+ @Test
+ public void testValidationOnConstructorReturnValue() throws Exception {
+ assertThatThrownBy( () -> new Foo( "" ) )
+ .isInstanceOf( ConstraintViolationException.class )
+ .hasMessageContaining( "size must be between 100 and 1000" );
+ }
+
+ public static class Foo {
+
+ @Size(min = 100, max = 1000)
+ private final String string;
+ private final int number;
+
+ public Foo(String string, int number) {
+ this.string = string;
+ this.number = number;
+ }
+
+ @Validate
+ public Foo(@Min(10) int number) {
+ this.number = number;
+ this.string = Integer.toString( number );
+ }
+
+ @Validate
+ @Valid
+ public Foo(String string) {
+ this.number = 10;
+ this.string = string;
+ }
+
+ @NotNull
+ @Validate
+ public String getString() {
+ return string;
+ }
+
+ @Validate
+ public void doNoting(@NotNull String justString) {
+
+ }
+
+ public int getNumber() {
+ return number;
+ }
+ }
+}
diff --git a/executable-validation/aspectj-validation/src/test/java/org/hibernate/validator/aspectj/validation/internal/ServiceLoaderBasedValidatorFactoryProducerTest.java b/executable-validation/aspectj-validation/src/test/java/org/hibernate/validator/aspectj/validation/internal/ServiceLoaderBasedValidatorFactoryProducerTest.java
new file mode 100644
index 0000000000..f50cb6b90f
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/test/java/org/hibernate/validator/aspectj/validation/internal/ServiceLoaderBasedValidatorFactoryProducerTest.java
@@ -0,0 +1,31 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+package org.hibernate.validator.aspectj.validation.internal;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.ServiceLoader;
+
+import javax.validation.ValidatorFactory;
+
+import org.testng.annotations.Test;
+
+/**
+ * @author Marko Bekhta
+ */
+public class ServiceLoaderBasedValidatorFactoryProducerTest {
+
+ /**
+ * Test that producer is correctly loaded by {@link ServiceLoader} by checking the type of configured clock provider.
+ */
+ @Test
+ public void testGetValidatorFactory() throws Exception {
+ ServiceLoaderBasedValidatorFactoryProducer producer = new ServiceLoaderBasedValidatorFactoryProducer();
+ ValidatorFactory validatorFactory = producer.getValidatorFactory();
+ assertThat( validatorFactory.getClockProvider() ).isInstanceOf( ValidatorFactoryProducerTestImpl.FixedClockProvider.class );
+ }
+}
diff --git a/executable-validation/aspectj-validation/src/test/java/org/hibernate/validator/aspectj/validation/internal/ValidatorFactoryProducerTestImpl.java b/executable-validation/aspectj-validation/src/test/java/org/hibernate/validator/aspectj/validation/internal/ValidatorFactoryProducerTestImpl.java
new file mode 100644
index 0000000000..6fce867a56
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/test/java/org/hibernate/validator/aspectj/validation/internal/ValidatorFactoryProducerTestImpl.java
@@ -0,0 +1,40 @@
+/*
+ * Hibernate Validator, declare and validate application constraints
+ *
+ * License: Apache License, Version 2.0
+ * See the license.txt file in the root directory or .
+ */
+package org.hibernate.validator.aspectj.validation.internal;
+
+import java.time.Clock;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+
+import javax.validation.ClockProvider;
+import javax.validation.Validation;
+import javax.validation.ValidatorFactory;
+
+import org.hibernate.validator.aspectj.validation.spi.ValidatorFactoryProducer;
+
+/**
+ * @author Marko Bekhta
+ */
+public class ValidatorFactoryProducerTestImpl implements ValidatorFactoryProducer {
+
+ @Override
+ public ValidatorFactory getConfiguredValidatorFactory() {
+ return Validation.byDefaultProvider().configure()
+ .clockProvider( new FixedClockProvider() )
+ .buildValidatorFactory();
+ }
+
+ public static class FixedClockProvider implements ClockProvider {
+
+ @Override
+ public Clock getClock() {
+ ZonedDateTime dateTime = ZonedDateTime.of( LocalDateTime.of( 2018, 3, 13, 0, 0 ), ZoneOffset.ofHours( 0 ) );
+ return Clock.fixed( dateTime.toInstant(), dateTime.getZone() );
+ }
+ }
+}
diff --git a/executable-validation/aspectj-validation/src/test/resources/META-INF/services/org.hibernate.validator.aspectj.validation.spi.ValidatorFactoryProducer b/executable-validation/aspectj-validation/src/test/resources/META-INF/services/org.hibernate.validator.aspectj.validation.spi.ValidatorFactoryProducer
new file mode 100644
index 0000000000..41fac58aea
--- /dev/null
+++ b/executable-validation/aspectj-validation/src/test/resources/META-INF/services/org.hibernate.validator.aspectj.validation.spi.ValidatorFactoryProducer
@@ -0,0 +1 @@
+org.hibernate.validator.aspectj.validation.internal.ValidatorFactoryProducerTestImpl
diff --git a/executable-validation/pom.xml b/executable-validation/pom.xml
new file mode 100644
index 0000000000..1daebdd201
--- /dev/null
+++ b/executable-validation/pom.xml
@@ -0,0 +1,49 @@
+
+
+
+ 4.0.0
+
+
+ org.hibernate.validator
+ hibernate-validator-parent
+ 6.0.9-SNAPSHOT
+ ../pom.xml
+
+
+ hibernate-validator-executable-validation
+ pom
+
+ Hibernate Validator Executable Validation
+ Hibernate Validator Executable Validation modules aggregator
+
+
+ ..
+
+ 1.8.13
+
+
+
+ aspectj-validation
+
+
+
+
+
+ org.aspectj
+ aspectjrt
+ ${aspectj.version}
+
+
+ org.aspectj
+ aspectjtools
+ ${aspectj.version}
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index 5b36963f08..9e9399ff9f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -90,6 +90,7 @@
modules
tck-runner
annotation-processor
+ executable-validation
integration
performance
osgi