From 711f071775021660a43ddb8e024725b396eb9440 Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Thu, 15 Mar 2018 19:08:07 +0100 Subject: [PATCH] Added new module with validation aspect - added new module - created an aspect to validate methods and constructors - added validator factory producer to get initialized validation factory --- .../aspectj-validation/pom.xml | 143 ++++++++++++++++++ .../aspectj/validation/Validate.java | 33 ++++ ...ceLoaderBasedValidatorFactoryProducer.java | 68 +++++++++ .../validation/internal/ValidationAspect.aj | 125 +++++++++++++++ .../validation/internal/package-info.java | 10 ++ .../validation/internal/util/logging/Log.java | 42 +++++ .../internal/util/logging/LoggerFactory.java | 29 ++++ .../formatter/ClassObjectFormatter.java | 26 ++++ .../util/logging/formatter/package-info.java | 12 ++ .../internal/util/logging/package-info.java | 11 ++ .../internal/util/package-info.java | 10 ++ ...datorProviderFactoryFromServiceLoader.java | 45 ++++++ .../util/privilegedactions/package-info.java | 12 ++ .../aspectj/validation/package-info.java | 13 ++ .../spi/ValidatorFactoryProducer.java | 25 +++ .../aspectj/validation/spi/package-info.java | 14 ++ .../internal/AspectValidationTest.java | 95 ++++++++++++ ...aderBasedValidatorFactoryProducerTest.java | 31 ++++ .../ValidatorFactoryProducerTestImpl.java | 40 +++++ ...tj.validation.spi.ValidatorFactoryProducer | 1 + executable-validation/pom.xml | 49 ++++++ pom.xml | 1 + 22 files changed, 835 insertions(+) create mode 100644 executable-validation/aspectj-validation/pom.xml create mode 100644 executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/Validate.java create mode 100644 executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/ServiceLoaderBasedValidatorFactoryProducer.java create mode 100644 executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/ValidationAspect.aj create mode 100644 executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/package-info.java create mode 100644 executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/Log.java create mode 100644 executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/LoggerFactory.java create mode 100644 executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/formatter/ClassObjectFormatter.java create mode 100644 executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/formatter/package-info.java create mode 100644 executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/logging/package-info.java create mode 100644 executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/package-info.java create mode 100644 executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/privilegedactions/GetValidatorProviderFactoryFromServiceLoader.java create mode 100644 executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/util/privilegedactions/package-info.java create mode 100644 executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/package-info.java create mode 100644 executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/spi/ValidatorFactoryProducer.java create mode 100644 executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/spi/package-info.java create mode 100644 executable-validation/aspectj-validation/src/test/java/org/hibernate/validator/aspectj/validation/internal/AspectValidationTest.java create mode 100644 executable-validation/aspectj-validation/src/test/java/org/hibernate/validator/aspectj/validation/internal/ServiceLoaderBasedValidatorFactoryProducerTest.java create mode 100644 executable-validation/aspectj-validation/src/test/java/org/hibernate/validator/aspectj/validation/internal/ValidatorFactoryProducerTestImpl.java create mode 100644 executable-validation/aspectj-validation/src/test/resources/META-INF/services/org.hibernate.validator.aspectj.validation.spi.ValidatorFactoryProducer create mode 100644 executable-validation/pom.xml diff --git a/executable-validation/aspectj-validation/pom.xml b/executable-validation/aspectj-validation/pom.xml new file mode 100644 index 0000000000..797a74adb6 --- /dev/null +++ b/executable-validation/aspectj-validation/pom.xml @@ -0,0 +1,143 @@ + + + + 4.0.0 + + org.hibernate.validator + hibernate-validator-executable-validation + 6.0.9-SNAPSHOT + + hibernate-validator-aspectj-validation + + Hibernate Validator AspectJ Validation + + + ../.. + org.hibernate.validator.aspectj.validation + + + + + + maven-checkstyle-plugin + + + de.thetaphi + forbiddenapis + + + maven-jar-plugin + + + default-jar + package + + jar + + + + + ${automatic.module.name} + + + + + + + + org.codehaus.mojo + aspectj-maven-plugin + 1.11 + + 1.8 + ${maven.compiler.source} + ${maven.compiler.target} + true + true + ignore + UTF-8 + + **/logging/*.* + + + + + + compile + test-compile + + + + + + + + + + + javax.validation + validation-api + + + org.jboss.logging + jboss-logging + + + + + org.aspectj + aspectjrt + provided + + + org.jboss.logging + jboss-logging-processor + + provided + + + org.jboss.logging + jboss-logging-annotations + provided + + + + + ${project.groupId} + hibernate-validator + test + + + ${project.groupId} + hibernate-validator-test-utils + test + + + org.glassfish + javax.el + test + + + org.testng + testng + test + + + org.assertj + assertj-core + test + + + diff --git a/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/Validate.java b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/Validate.java new file mode 100644 index 0000000000..895bedad18 --- /dev/null +++ b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/Validate.java @@ -0,0 +1,33 @@ +/* + * 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; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.validation.groups.Default; + +/** + * Marker annotation to filter the methods/constructors validation of + * which should be performed. + * + * @author Marko Bekhta + */ +@Target({ METHOD, /*TYPE,*/ CONSTRUCTOR }) +@Retention(RUNTIME) +public @interface Validate { + + /** + * @return an array of validation groups for which validation should be applied. + * Is empty by default, hence validation will run for {@link Default} group. + */ + Class[] groups() default { }; +} diff --git a/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/ServiceLoaderBasedValidatorFactoryProducer.java b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/ServiceLoaderBasedValidatorFactoryProducer.java new file mode 100644 index 0000000000..daf0d35328 --- /dev/null +++ b/executable-validation/aspectj-validation/src/main/java/org/hibernate/validator/aspectj/validation/internal/ServiceLoaderBasedValidatorFactoryProducer.java @@ -0,0 +1,68 @@ +/* + * 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.lang.invoke.MethodHandles; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.List; +import java.util.ServiceLoader; + +import javax.validation.Validation; +import javax.validation.ValidatorFactory; + +import org.hibernate.validator.aspectj.validation.internal.util.logging.Log; +import org.hibernate.validator.aspectj.validation.internal.util.logging.LoggerFactory; +import org.hibernate.validator.aspectj.validation.internal.util.privilegedactions.GetValidatorProviderFactoryFromServiceLoader; +import org.hibernate.validator.aspectj.validation.spi.ValidatorFactoryProducer; + +/** + * Uses {@link ServiceLoader} mechanism to look up user provided {@link ValidatorFactoryProducer}. + * If none are found will provide a default {@link ValidatorFactory}. + * + * @author Marko Bekhta + */ +class ServiceLoaderBasedValidatorFactoryProducer { + + private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() ); + + private final ValidatorFactory validatorFactory; + + ServiceLoaderBasedValidatorFactoryProducer() { + List 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 aClass); + + @Message(id = 3, value = "Unable to create ValidatorFactory using %1$s producer.") + IllegalStateException errorCreatingValidatorFactoryFromProducer(@FormatWith(ClassObjectFormatter.class) Class 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