BV2: new validation implementation
Project: http://git-wip-us.apache.org/repos/asf/bval/repo Commit: http://git-wip-us.apache.org/repos/asf/bval/commit/05df7ee2 Tree: http://git-wip-us.apache.org/repos/asf/bval/tree/05df7ee2 Diff: http://git-wip-us.apache.org/repos/asf/bval/diff/05df7ee2 Branch: refs/heads/bv2 Commit: 05df7ee264cbef9199897b170e89bb7fcac58f26 Parents: a921963 Author: Matt Benson <[email protected]> Authored: Wed Feb 21 14:54:03 2018 -0600 Committer: Matt Benson <[email protected]> Committed: Wed Feb 21 14:59:58 2018 -0600 ---------------------------------------------------------------------- .../apache/bval/jsr/ApacheFactoryContext.java | 83 ++++++--- .../bval/jsr/ApacheValidatorConfiguration.java | 7 +- .../apache/bval/jsr/ApacheValidatorFactory.java | 171 ++++++++++++------- .../bval/jsr/BootstrapConfigurationImpl.java | 29 +++- .../bval/jsr/CascadingPropertyValidator.java | 96 ++++++++--- .../org/apache/bval/jsr/ConfigurationImpl.java | 128 ++++++++------ .../java/org/apache/bval/jsr/ValidatorImpl.java | 141 +++++++++++++++ 7 files changed, 494 insertions(+), 161 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/bval/blob/05df7ee2/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java index 8f68b9e..1e4b263 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java @@ -18,46 +18,56 @@ */ package org.apache.bval.jsr; -import org.apache.bval.MetaBeanFinder; -import org.apache.bval.util.reflection.Reflection; -import org.apache.commons.weaver.privilizer.Privilizing; -import org.apache.commons.weaver.privilizer.Privilizing.CallTo; - +import javax.validation.ClockProvider; import javax.validation.ConstraintValidatorFactory; import javax.validation.MessageInterpolator; import javax.validation.ParameterNameProvider; import javax.validation.TraversableResolver; import javax.validation.Validator; import javax.validation.ValidatorContext; +import javax.validation.valueextraction.ValueExtractor; + +import org.apache.bval.MetaBeanFinder; +import org.apache.bval.jsr.descriptor.DescriptorManager; +import org.apache.bval.jsr.groups.GroupsComputer; +import org.apache.bval.jsr.valueextraction.ValueExtractors; +import org.apache.bval.util.Lazy; +import org.apache.bval.util.reflection.Reflection; +import org.apache.commons.weaver.privilizer.Privilizing; +import org.apache.commons.weaver.privilizer.Privilizing.CallTo; /** - * Description: Represents the context that is used to create - * {@link ClassValidator} instances. + * Description: Represents the context that is used to create {@link ClassValidator} instances. */ @Privilizing(@CallTo(Reflection.class)) public class ApacheFactoryContext implements ValidatorContext { + private final Lazy<GroupsComputer> groupsComputer = new Lazy<>(GroupsComputer::new); private final ApacheValidatorFactory factory; + private final ValueExtractors valueExtractors; private volatile MetaBeanFinder metaBeanFinder; private MessageInterpolator messageInterpolator; private TraversableResolver traversableResolver; private ParameterNameProvider parameterNameProvider; private ConstraintValidatorFactory constraintValidatorFactory; + private ClockProvider clockProvider; /** * Create a new ApacheFactoryContext instance. * - * @param factory validator factory - * @param metaBeanFinder meta finder + * @param factory + * validator factory + * @param metaBeanFinder + * meta finder */ public ApacheFactoryContext(ApacheValidatorFactory factory, MetaBeanFinder metaBeanFinder) { this.factory = factory; this.metaBeanFinder = metaBeanFinder; + valueExtractors = factory.getValueExtractors().createChild(); } /** - * Get the {@link ApacheValidatorFactory} used by this - * {@link ApacheFactoryContext}. + * Get the {@link ApacheValidatorFactory} used by this {@link ApacheFactoryContext}. * * @return {@link ApacheValidatorFactory} */ @@ -75,13 +85,13 @@ public class ApacheFactoryContext implements ValidatorContext { } /** - * Discard cached metadata. Calling this method unnecessarily has the effect of severly - * limiting performance, therefore only do so when changes have been made that affect - * validation metadata, i.e. particularly NOT in response to: + * Discard cached metadata. Calling this method unnecessarily has the effect of severly limiting performance, + * therefore only do so when changes have been made that affect validation metadata, i.e. particularly NOT in + * response to: * <ul> - * <li>{@link #messageInterpolator(MessageInterpolator)}</li> - * <li>{@link #traversableResolver(TraversableResolver)}</li> - * <li>{@link #constraintValidatorFactory(ConstraintValidatorFactory)</li> + * <li>{@link #messageInterpolator(MessageInterpolator)}</li> + * <li>{@link #traversableResolver(TraversableResolver)}</li> + * <li>{@link #constraintValidatorFactory(ConstraintValidatorFactory)</li> * </ul> */ private synchronized void resetMeta() { @@ -92,7 +102,7 @@ public class ApacheFactoryContext implements ValidatorContext { * {@inheritDoc} */ @Override - public ValidatorContext messageInterpolator(MessageInterpolator messageInterpolator) { + public ApacheFactoryContext messageInterpolator(MessageInterpolator messageInterpolator) { this.messageInterpolator = messageInterpolator; return this; } @@ -101,7 +111,7 @@ public class ApacheFactoryContext implements ValidatorContext { * {@inheritDoc} */ @Override - public ValidatorContext traversableResolver(TraversableResolver traversableResolver) { + public ApacheFactoryContext traversableResolver(TraversableResolver traversableResolver) { this.traversableResolver = traversableResolver; return this; } @@ -110,18 +120,30 @@ public class ApacheFactoryContext implements ValidatorContext { * {@inheritDoc} */ @Override - public ValidatorContext constraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory) { + public ApacheFactoryContext constraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory) { this.constraintValidatorFactory = constraintValidatorFactory; return this; } @Override - public ValidatorContext parameterNameProvider(ParameterNameProvider parameterNameProvider) { + public ApacheFactoryContext parameterNameProvider(ParameterNameProvider parameterNameProvider) { this.parameterNameProvider = parameterNameProvider; resetMeta(); // needed since parameter names are a component of validation metadata return this; } + @Override + public ApacheFactoryContext clockProvider(ClockProvider clockProvider) { + this.clockProvider = clockProvider; + return this; + } + + @Override + public ApacheFactoryContext addValueExtractor(ValueExtractor<?> extractor) { + valueExtractors.add(extractor); + return this; + } + /** * Get the {@link ConstraintValidatorFactory}. * @@ -137,7 +159,7 @@ public class ApacheFactoryContext implements ValidatorContext { */ @Override public Validator getValidator() { - return new ClassValidator(this); + return new ValidatorImpl(this); } /** @@ -162,6 +184,23 @@ public class ApacheFactoryContext implements ValidatorContext { return parameterNameProvider == null ? factory.getParameterNameProvider() : parameterNameProvider; } + public ClockProvider getClockProvider() { + return clockProvider == null ? factory.getClockProvider() : clockProvider; + } + + public ValueExtractors getValueExtractors() { + return valueExtractors; + } + + public DescriptorManager getDescriptorManager() { + // TODO handle context customizations + return factory.getDescriptorManager(); + } + + public GroupsComputer getGroupsComputer() { + return groupsComputer.get(); + } + boolean isTreatMapsLikeBeans() { return Boolean .parseBoolean(factory.getProperties().get(ApacheValidatorConfiguration.Properties.TREAT_MAPS_LIKE_BEANS)); http://git-wip-us.apache.org/repos/asf/bval/blob/05df7ee2/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorConfiguration.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorConfiguration.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorConfiguration.java index fb64d4e..81187f3 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorConfiguration.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorConfiguration.java @@ -32,7 +32,7 @@ public interface ApacheValidatorConfiguration extends Configuration<ApacheValida /** * Proprietary property keys for {@link ConfigurationImpl} */ - public interface Properties { + interface Properties { /** * the location where to look for the validation.xml file. * default: "META-INF/validation.xml" @@ -91,5 +91,10 @@ public interface ApacheValidatorConfiguration extends Configuration<ApacheValida * </ol> */ String METABEAN_FACTORY_CLASSNAMES = "apache.bval.metabean-factory-classnames"; + + /** + * Size to use for caching of constraint-related information. Default is {@code 50}. + */ + String CONSTRAINTS_CACHE_SIZE = "apache.bval.constraints-cache-size"; } } http://git-wip-us.apache.org/repos/asf/bval/blob/05df7ee2/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java index 5e6a611..b516a73 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java @@ -18,11 +18,39 @@ */ package org.apache.bval.jsr; +import java.io.Closeable; +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import javax.validation.ClockProvider; +import javax.validation.ConstraintValidatorFactory; +import javax.validation.MessageInterpolator; +import javax.validation.ParameterNameProvider; +import javax.validation.TraversableResolver; +import javax.validation.Validation; +import javax.validation.ValidationException; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; +import javax.validation.spi.ConfigurationState; + import org.apache.bval.IntrospectorMetaBeanFactory; import org.apache.bval.MetaBeanBuilder; import org.apache.bval.MetaBeanFactory; import org.apache.bval.MetaBeanFinder; import org.apache.bval.MetaBeanManager; +import org.apache.bval.jsr.descriptor.DescriptorManager; +import org.apache.bval.jsr.metadata.MetadataBuilders; +import org.apache.bval.jsr.util.AnnotationsManager; +import org.apache.bval.jsr.valueextraction.ValueExtractors; import org.apache.bval.jsr.xml.AnnotationIgnores; import org.apache.bval.jsr.xml.MetaConstraint; import org.apache.bval.jsr.xml.ValidationMappingParser; @@ -37,28 +65,6 @@ import org.apache.commons.weaver.privilizer.Privileged; import org.apache.commons.weaver.privilizer.Privilizing; import org.apache.commons.weaver.privilizer.Privilizing.CallTo; -import javax.validation.ConstraintValidatorFactory; -import javax.validation.MessageInterpolator; -import javax.validation.ParameterNameProvider; -import javax.validation.TraversableResolver; -import javax.validation.Validation; -import javax.validation.ValidationException; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; -import javax.validation.spi.ConfigurationState; -import java.io.Closeable; -import java.lang.annotation.Annotation; -import java.lang.reflect.Constructor; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - /** * Description: a factory is a complete configurated object that can create * validators.<br/> @@ -68,13 +74,17 @@ import java.util.concurrent.ConcurrentMap; public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { private static volatile ApacheValidatorFactory DEFAULT_FACTORY; - private static final ConstraintDefaults DEFAULT_CONSTRAINTS = new ConstraintDefaults(); private MessageInterpolator messageResolver; private TraversableResolver traversableResolver; private ConstraintValidatorFactory constraintValidatorFactory; private ParameterNameProvider parameterNameProvider; + private ClockProvider clockProvider; private final Map<String, String> properties; + private final AnnotationsManager annotationsManager; + private final DescriptorManager descriptorManager = new DescriptorManager(this); + private final MetadataBuilders metadataBuilders = new MetadataBuilders(); + private final ValueExtractors valueExtractors = new ValueExtractors(); /** * information from xml parsing @@ -89,7 +99,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { private final ConcurrentMap<Class<?>, List<AccessStrategy>> validAccesses; private final ConcurrentMap<Class<?>, List<MetaConstraint<?, ? extends Annotation>>> constraintMap; - private final Collection<Closeable> toClose = new ArrayList<Closeable>(); + private final Collection<Closeable> toClose = new ArrayList<>(); private final MetaBeanFinder defaultMetaBeanFinder; /** @@ -112,7 +122,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { * @return a new instance of MetaBeanManager with adequate MetaBeanFactories */ protected MetaBeanFinder buildMetaBeanFinder() { - final List<MetaBeanFactory> builders = new ArrayList<MetaBeanFactory>(); + final List<MetaBeanFactory> builders = new ArrayList<>(); if (Boolean.parseBoolean(getProperties().get(ApacheValidatorConfiguration.Properties.ENABLE_INTROSPECTOR))) { builders.add(new IntrospectorMetaBeanFactory()); } @@ -121,9 +131,8 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { if (factoryClassNames != null) { for (String clsName : factoryClassNames) { // cast, relying on #createMetaBeanFactory to throw the exception if incompatible: - @SuppressWarnings("unchecked") final Class<? extends MetaBeanFactory> factoryClass = - (Class<? extends MetaBeanFactory>) loadClass(clsName); + loadClass(clsName).asSubclass(MetaBeanFactory.class); builders.add(createMetaBeanFactory(factoryClass)); } } @@ -173,24 +182,27 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { * Create a new ApacheValidatorFactory instance. */ public ApacheValidatorFactory(ConfigurationState configuration) { - properties = new HashMap<String, String>(configuration.getProperties()); - defaultSequences = new HashMap<Class<?>, Class<?>[]>(); - validAccesses = new ConcurrentHashMap<Class<?>, List<AccessStrategy>>(); - constraintMap = new ConcurrentHashMap<Class<?>, List<MetaConstraint<?, ? extends Annotation>>>(); + properties = new HashMap<>(configuration.getProperties()); + defaultSequences = new HashMap<>(); + validAccesses = new ConcurrentHashMap<>(); + constraintMap = new ConcurrentHashMap<>(); parameterNameProvider = configuration.getParameterNameProvider(); messageResolver = configuration.getMessageInterpolator(); traversableResolver = configuration.getTraversableResolver(); constraintValidatorFactory = configuration.getConstraintValidatorFactory(); + clockProvider = configuration.getClockProvider(); if (ConfigurationImpl.class.isInstance(configuration)) { - final ConfigurationImpl impl = ConfigurationImpl.class.cast(configuration); - toClose.add(impl.getClosable()); + toClose.add(ConfigurationImpl.class.cast(configuration).getClosable()); } new ValidationMappingParser(this).processMappingConfig(configuration.getMappingStreams()); defaultMetaBeanFinder = buildMetaBeanFinder(); + + configuration.getValueExtractors().forEach(valueExtractors::add); + annotationsManager = new AnnotationsManager(this); } /** @@ -203,8 +215,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } /** - * Shortcut method to create a new Validator instance with factory's - * settings + * Shortcut method to create a new Validator instance with factory's settings * * @return the new validator instance */ @@ -271,6 +282,12 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } } + public void setClockProvider(final ClockProvider clockProvider) { + if (clockProvider != null) { + this.clockProvider = clockProvider; + } + } + /** * {@inheritDoc} */ @@ -307,6 +324,11 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } @Override + public ClockProvider getClockProvider() { + return clockProvider; + } + + @Override public void close() { try { for (final Closeable c : toClose) { @@ -319,13 +341,14 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } /** - * Return an object of the specified type to allow access to the - * provider-specific API. If the Bean Validation provider implementation - * does not support the specified class, the ValidationException is thrown. + * Return an object of the specified type to allow access to the provider-specific API. If the Bean Validation + * provider implementation does not support the specified class, the ValidationException is thrown. * - * @param type the class of the object to be returned. + * @param type + * the class of the object to be returned. * @return an instance of the specified class - * @throws ValidationException if the provider does not support the call. + * @throws ValidationException + * if the provider does not support the call. */ @Override public <T> T unwrap(final Class<T> type) { @@ -365,15 +388,6 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } /** - * Get the detected {@link ConstraintDefaults}. - * - * @return ConstraintDefaults - */ - public ConstraintDefaults getDefaultConstraints() { - return DEFAULT_CONSTRAINTS; - } - - /** * Get the detected {@link AnnotationIgnores}. * * @return AnnotationIgnores @@ -392,8 +406,34 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } /** - * Add a meta-constraint to this {@link ApacheValidatorFactory}'s runtime - * customizations. + * Get the {@link AnnotationsManager}. + * + * @return {@link AnnotationsManager} + */ + public AnnotationsManager getAnnotationsManager() { + return annotationsManager; + } + + /** + * Get the {@link DescriptorManager}. + * + * @return {@link DescriptorManager} + */ + public DescriptorManager getDescriptorManager() { + return descriptorManager; + } + + /** + * Get the {@link ValueExtractors}. + * + * @return {@link ValueExtractors} + */ + public ValueExtractors getValueExtractors() { + return valueExtractors; + } + + /** + * Add a meta-constraint to this {@link ApacheValidatorFactory}'s runtime customizations. * * @param beanClass * @param metaConstraint @@ -401,7 +441,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { public void addMetaConstraint(final Class<?> beanClass, final MetaConstraint<?, ?> metaConstraint) { List<MetaConstraint<?, ? extends Annotation>> slot = constraintMap.get(beanClass); if (slot == null) { - slot = new ArrayList<MetaConstraint<?, ? extends Annotation>>(); + slot = new ArrayList<>(); final List<MetaConstraint<?, ? extends Annotation>> old = constraintMap.putIfAbsent(beanClass, slot); if (old != null) { slot = old; @@ -420,7 +460,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { public void addValid(Class<?> beanClass, AccessStrategy accessStrategy) { List<AccessStrategy> slot = validAccesses.get(beanClass); if (slot == null) { - slot = new ArrayList<AccessStrategy>(); + slot = new ArrayList<>(); final List<AccessStrategy> old = validAccesses.putIfAbsent(beanClass, slot); if (old != null) { slot = old; @@ -444,8 +484,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { * * @param <T> * @param beanClass - * @return List of {@link MetaConstraint}s applicable to - * <code>beanClass</code> + * @return List of {@link MetaConstraint}s applicable to <code>beanClass</code> */ public <T> List<MetaConstraint<T, ? extends Annotation>> getMetaConstraints(Class<T> beanClass) { final List<MetaConstraint<?, ? extends Annotation>> slot = constraintMap.get(beanClass); @@ -459,16 +498,15 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } /** - * Get the {@link AccessStrategy} {@link List} indicating nested bean - * validations that must be triggered in the course of validating a - * <code>beanClass</code> graph. + * Get the {@link AccessStrategy} {@link List} indicating nested bean validations that must be triggered in the + * course of validating a <code>beanClass</code> graph. * * @param beanClass * @return {@link List} of {@link AccessStrategy} */ public List<AccessStrategy> getValidAccesses(Class<?> beanClass) { final List<AccessStrategy> slot = validAccesses.get(beanClass); - return slot == null ? Collections.<AccessStrategy> emptyList() : Collections.unmodifiableList(slot); + return slot == null ? Collections.emptyList() : Collections.unmodifiableList(slot); } /** @@ -481,6 +519,10 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { return safeArray(defaultSequences.get(beanClass)); } + public MetadataBuilders getMetadataBuilders() { + return metadataBuilders; + } + private static Class<?>[] safeArray(Class<?>... array) { return array == null || array.length == 0 ? ObjectUtils.EMPTY_CLASS_ARRAY : array.clone(); } @@ -519,9 +561,8 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } /** - * separate class to prevent the classloader to immediately load optional - * classes: XMLMetaBeanManager, XMLMetaBeanFactory, XMLMetaBeanBuilder that - * might not be available in the classpath + * separate class to prevent the classloader to immediately load optional classes: XMLMetaBeanManager, + * XMLMetaBeanFactory, XMLMetaBeanBuilder that might not be available in the classpath */ private static class XMLMetaBeanManagerCreator { @@ -530,10 +571,10 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } /** - * Create the {@link MetaBeanManager} to process JSR303 XML. Requires - * bval-xstream at RT. + * Create the {@link MetaBeanManager} to process JSR303 XML. Requires bval-xstream at RT. * - * @param builders meta bean builders + * @param builders + * meta bean builders * @return {@link MetaBeanManager} */ // NOTE - We return MetaBeanManager instead of XMLMetaBeanManager to http://git-wip-us.apache.org/repos/asf/bval/blob/05df7ee2/bval-jsr/src/main/java/org/apache/bval/jsr/BootstrapConfigurationImpl.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/BootstrapConfigurationImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/BootstrapConfigurationImpl.java index 3a3abf1..d85ab51 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/BootstrapConfigurationImpl.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/BootstrapConfigurationImpl.java @@ -34,12 +34,15 @@ public class BootstrapConfigurationImpl implements BootstrapConfiguration { private String messageInterpolatorClassName; private String constraintValidatorFactoryClassName; private String defaultProviderClassName; + private String clockProviderClassName; + private Set<String> valueExtractorClassNames; public BootstrapConfigurationImpl(final String defaultProviderClassName, final String constraintValidatorFactoryClassName, final String messageInterpolatorClassName, final String traversableResolverClassName, final String parameterNameProviderClassName, final Set<String> constraintMappingResourcePaths, final boolean executableValidationEnabled, - final Set<ExecutableType> defaultValidatedExecutableTypes, final Map<String, String> properties) { + final Set<ExecutableType> defaultValidatedExecutableTypes, final Map<String, String> properties, + final String clockProviderClassName, final Set<String> valueExtractorClassNames) { this.properties = Collections.unmodifiableMap(properties); this.defaultValidatedExecutableTypes = Collections.unmodifiableSet(defaultValidatedExecutableTypes); this.executableValidationEnabled = executableValidationEnabled; @@ -49,6 +52,8 @@ public class BootstrapConfigurationImpl implements BootstrapConfiguration { this.messageInterpolatorClassName = messageInterpolatorClassName; this.constraintValidatorFactoryClassName = constraintValidatorFactoryClassName; this.defaultProviderClassName = defaultProviderClassName; + this.clockProviderClassName = clockProviderClassName; + this.valueExtractorClassNames = valueExtractorClassNames; } @Override @@ -78,7 +83,7 @@ public class BootstrapConfigurationImpl implements BootstrapConfiguration { @Override public Set<String> getConstraintMappingResourcePaths() { - return constraintMappingResourcePaths; + return Collections.unmodifiableSet(constraintMappingResourcePaths); } @Override @@ -88,11 +93,27 @@ public class BootstrapConfigurationImpl implements BootstrapConfiguration { @Override public Set<ExecutableType> getDefaultValidatedExecutableTypes() { - return defaultValidatedExecutableTypes; + return Collections.unmodifiableSet(defaultValidatedExecutableTypes); } @Override public Map<String, String> getProperties() { - return properties; + return Collections.unmodifiableMap(properties); + } + + /** + * @since 2.0 + */ + @Override + public String getClockProviderClassName() { + return clockProviderClassName; + } + + /** + * @since 2.0 + */ + @Override + public Set<String> getValueExtractorClassNames() { + return Collections.unmodifiableSet(valueExtractorClassNames); } } http://git-wip-us.apache.org/repos/asf/bval/blob/05df7ee2/bval-jsr/src/main/java/org/apache/bval/jsr/CascadingPropertyValidator.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/CascadingPropertyValidator.java b/bval-jsr/src/main/java/org/apache/bval/jsr/CascadingPropertyValidator.java index ff2e273..f183c12 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/CascadingPropertyValidator.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/CascadingPropertyValidator.java @@ -18,7 +18,9 @@ package org.apache.bval.jsr; import javax.validation.ConstraintViolation; import javax.validation.Valid; +import javax.validation.ValidationException; import javax.validation.Validator; + import java.util.Set; /** @@ -30,38 +32,90 @@ import java.util.Set; * It should be noted that {@link Validator#validateProperty(Object, String, Class...)} * and {@link Validator#validateValue(Class, String, Object, Class...)} are assumed * semantically equivalent to calling the {@link CascadingPropertyValidator}-defined - * methods with <code>cascade == false</code>. + * methods with {@code cascade == false}. * * @version $Rev: 993539 $ $Date: 2010-09-07 16:27:50 -0500 (Tue, 07 Sep 2010) $ */ public interface CascadingPropertyValidator extends Validator { /** - * Validates all constraints placed on <code>object</code>'s - * <code>propertyName</code> property, with optional validation cascading. - * - * @param <T> - * @param object - * @param propertyName - * @param cascade - * @param groups - * @return the resulting {@link Set} of {@link ConstraintViolation}s. + * {@inheritDoc} Validates all constraints placed on the property of {@code object} named {@code propertyName}. + * + * @param object object to validate + * @param propertyName property to validate (i.e. field and getter constraints). Nested + * properties may be referenced (e.g. prop[2].subpropA.subpropB) + * @param groups group or list of groups targeted for validation (default to + * {@link javax.validation.groups.Default}) + * @return constraint violations or an empty {@link Set} if none + * @throws IllegalArgumentException if {@code object} is {@code null}, if {@code propertyName null}, + * empty or not a valid object property or if {@code null} is + * passed to the varargs {@code groups} + * @throws ValidationException if a non recoverable error happens during the validation process + */ + @Override + default <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, Class<?>... groups) { + return validateProperty(object, propertyName, false, groups); + } + + /** + * Validates all constraints placed on the property of {@code object} named {@code propertyName}. + * + * @param object object to validate + * @param propertyName property to validate (i.e. field and getter constraints). Nested + * properties may be referenced (e.g. prop[2].subpropA.subpropB) + * @param cascade whether to cascade along {@link Valid} properties + * @param groups group or list of groups targeted for validation (default to + * {@link javax.validation.groups.Default}) + * @return constraint violations or an empty {@link Set} if none + * @throws IllegalArgumentException if {@code object} is {@code null}, if {@code propertyName null}, + * empty or not a valid object property or if {@code null} is + * passed to the varargs {@code groups} + * @throws ValidationException if a non recoverable error happens during the validation process */ <T> Set<javax.validation.ConstraintViolation<T>> validateProperty(T object, String propertyName, boolean cascade, Class<?>... groups); /** - * Validates all constraints placed on <code>object</code>'s - * <code>propertyName</code> property, with optional validation cascading, - * given a hypothetical property <code>value</code>. - * - * @param <T> - * @param beanType - * @param propertyName - * @param value - * @param cascade - * @param groups - * @return the resulting {@link Set} of {@link ConstraintViolation}s. + * {@inheritDoc} Validates all constraints placed on the property named {@code propertyName} of the class + * {@code beanType} would the property value be {@code value}. + * <p/> + * {@link ConstraintViolation} objects return {@code null} for {@link ConstraintViolation#getRootBean()} and + * {@link ConstraintViolation#getLeafBean()}. + * + * @param beanType the bean type + * @param propertyName property to validate + * @param value property value to validate + * @param groups group or list of groups targeted for validation (default to + * {@link javax.validation.groups.Default}) + * @return constraint violations or an empty {@link Set} if none + * @throws IllegalArgumentException if {@code beanType} is {@code null}, if + * {@code propertyName null}, empty or not a valid object + * property or if {@code null} is passed to the varargs {@code groups} + * @throws ValidationException if a non recoverable error happens during the validation process + */ + @Override + default <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, + Class<?>... groups) { + return validateValue(beanType, propertyName, value, false, groups); + } + + /** + * {@inheritDoc} Validates all constraints placed on the property named {@code propertyName} of the class + * {@code beanType} would the property value be {@code value}. + * <p/> + * {@link ConstraintViolation} objects return {@code null} for {@link ConstraintViolation#getRootBean()} and + * {@link ConstraintViolation#getLeafBean()}. + * + * @param beanType the bean type + * @param propertyName property to validate + * @param value property value to validate + * @param groups group or list of groups targeted for validation (default to + * {@link javax.validation.groups.Default}) + * @return constraint violations or an empty {@link Set} if none + * @throws IllegalArgumentException if {@code beanType} is {@code null}, if + * {@code propertyName null}, empty or not a valid object + * property or if {@code null} is passed to the varargs {@code groups} + * @throws ValidationException if a non recoverable error happens during the validation process */ <T> Set<javax.validation.ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, boolean cascade, Class<?>... groups); http://git-wip-us.apache.org/repos/asf/bval/blob/05df7ee2/bval-jsr/src/main/java/org/apache/bval/jsr/ConfigurationImpl.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConfigurationImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConfigurationImpl.java index 7c4780f..046d6d2 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConfigurationImpl.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConfigurationImpl.java @@ -19,9 +19,10 @@ package org.apache.bval.jsr; import java.io.Closeable; -import java.io.IOException; import java.io.InputStream; +import java.time.Clock; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -29,6 +30,7 @@ import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import javax.validation.BootstrapConfiguration; +import javax.validation.ClockProvider; import javax.validation.ConstraintValidatorFactory; import javax.validation.MessageInterpolator; import javax.validation.ParameterNameProvider; @@ -40,6 +42,7 @@ import javax.validation.executable.ExecutableType; import javax.validation.spi.BootstrapState; import javax.validation.spi.ConfigurationState; import javax.validation.spi.ValidationProvider; +import javax.validation.valueextraction.ValueExtractor; import org.apache.bval.cdi.BValExtension; import org.apache.bval.jsr.parameter.DefaultParameterNameProvider; @@ -76,29 +79,33 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur */ protected MessageInterpolator defaultMessageInterpolator = new DefaultMessageInterpolator(); protected volatile MessageInterpolator messageInterpolator = defaultMessageInterpolator; - protected Class<? extends MessageInterpolator> messageInterpolatorClass = null; + protected Class<? extends MessageInterpolator> messageInterpolatorClass; /** * Configured {@link ConstraintValidatorFactory} */ protected ConstraintValidatorFactory defaultConstraintValidatorFactory = new DefaultConstraintValidatorFactory(); protected volatile ConstraintValidatorFactory constraintValidatorFactory = defaultConstraintValidatorFactory; - protected Class<? extends ConstraintValidatorFactory> constraintValidatorFactoryClass = null; + protected Class<? extends ConstraintValidatorFactory> constraintValidatorFactoryClass; protected TraversableResolver defaultTraversableResolver = new DefaultTraversableResolver(); protected volatile TraversableResolver traversableResolver = defaultTraversableResolver; - protected Class<? extends TraversableResolver> traversableResolverClass = null; + protected Class<? extends TraversableResolver> traversableResolverClass; protected ParameterNameProvider defaultParameterNameProvider = new DefaultParameterNameProvider(); protected volatile ParameterNameProvider parameterNameProvider = defaultParameterNameProvider; - protected Class<? extends ParameterNameProvider> parameterNameProviderClass = null; + protected Class<? extends ParameterNameProvider> parameterNameProviderClass; protected BootstrapConfiguration bootstrapConfiguration; protected Collection<ExecutableType> executableValidation; - private Collection<BValExtension.Releasable<?>> releasables = - new CopyOnWriteArrayList<BValExtension.Releasable<?>>(); + private Collection<BValExtension.Releasable<?>> releasables = new CopyOnWriteArrayList<>(); + protected ClockProvider defaultClockProvider = Clock::systemDefaultZone; + protected volatile ClockProvider clockProvider = defaultClockProvider; + protected Class<? extends ClockProvider> clockProviderClass; + + protected Set<ValueExtractor<?>> valueExtractors = new HashSet<>(); private boolean beforeCdi = false; @@ -109,8 +116,8 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur private boolean prepared = false; // END DEFAULTS - private Set<InputStream> mappingStreams = new HashSet<InputStream>(); - private Map<String, String> properties = new HashMap<String, String>(); + private Set<InputStream> mappingStreams = new HashSet<>(); + private Map<String, String> properties = new HashMap<>(); private boolean ignoreXmlConfiguration = false; private volatile ValidationParser parser; @@ -134,6 +141,7 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur } else { throw new ValidationException("either provider or state are required"); } + initializePropertyDefaults(); } /** @@ -141,13 +149,11 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur */ @Override public ApacheValidatorConfiguration traversableResolver(TraversableResolver resolver) { - if (resolver == null) { - return this; + if (resolver != null) { + this.traversableResolverClass = null; + this.traversableResolver = resolver; + this.prepared = false; } - - this.traversableResolverClass = null; - this.traversableResolver = resolver; - this.prepared = false; return this; } @@ -169,13 +175,11 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur */ @Override public ConfigurationImpl messageInterpolator(MessageInterpolator resolver) { - if (resolver == null) { - return this; + if (resolver != null) { + this.messageInterpolatorClass = null; + this.messageInterpolator = resolver; + this.prepared = false; } - - this.messageInterpolatorClass = null; - this.messageInterpolator = resolver; - this.prepared = false; return this; } @@ -184,23 +188,20 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur */ @Override public ConfigurationImpl constraintValidatorFactory(ConstraintValidatorFactory constraintFactory) { - if (constraintFactory == null) { - return this; + if (constraintFactory != null) { + this.constraintValidatorFactoryClass = null; + this.constraintValidatorFactory = constraintFactory; + this.prepared = false; } - - this.constraintValidatorFactoryClass = null; - this.constraintValidatorFactory = constraintFactory; - this.prepared = false; return this; } @Override public ApacheValidatorConfiguration parameterNameProvider(ParameterNameProvider parameterNameProvider) { - if (parameterNameProvider == null) { - return this; + if (parameterNameProvider != null) { + this.parameterNameProviderClass = null; + this.parameterNameProvider = parameterNameProvider; } - this.parameterNameProviderClass = null; - this.parameterNameProvider = parameterNameProvider; return this; } @@ -213,10 +214,9 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur */ @Override public ApacheValidatorConfiguration addMapping(InputStream stream) { - if (stream == null) { - return this; + if (stream != null) { + mappingStreams.add(IOs.convertToMarkableInputStream(stream)); } - mappingStreams.add(IOs.convertToMarkableInputStream(stream)); return this; } @@ -297,7 +297,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur if (beforeCdi) { return defaultMessageInterpolator; } - if (messageInterpolator == defaultMessageInterpolator && messageInterpolatorClass != null) { synchronized (this) { if (messageInterpolator == defaultMessageInterpolator && messageInterpolatorClass != null) { @@ -336,7 +335,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur if (prepared) { return this; } - createBootstrapConfiguration(); parser.applyConfigWithInstantiation(this); // instantiate the config if needed @@ -367,7 +365,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur if (beforeCdi) { return constraintValidatorFactory; } - if (constraintValidatorFactory == defaultConstraintValidatorFactory && constraintValidatorFactoryClass != null) { synchronized (this) { @@ -388,7 +385,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur if (beforeCdi) { return defaultTraversableResolver; } - if (traversableResolver == defaultTraversableResolver && traversableResolverClass != null) { synchronized (this) { if (traversableResolver == defaultTraversableResolver && traversableResolverClass != null) { @@ -404,7 +400,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur if (beforeCdi) { return defaultParameterNameProvider; } - if (parameterNameProvider == defaultParameterNameProvider && parameterNameProviderClass != null) { synchronized (this) { if (parameterNameProvider == defaultParameterNameProvider && parameterNameProviderClass != null) { @@ -452,14 +447,11 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur } public Closeable getClosable() { - return new Closeable() { - @Override - public void close() throws IOException { - for (final BValExtension.Releasable<?> releasable : releasables) { - releasable.release(); - } - releasables.clear(); + return () -> { + for (final BValExtension.Releasable<?> releasable : releasables) { + releasable.release(); } + releasables.clear(); }; } @@ -469,8 +461,7 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur final BValExtension.Releasable<T> releasable = BValExtension.inject(cls); releasables.add(releasable); return releasable.getInstance(); - } catch (final Exception e) { - } catch (final NoClassDefFoundError error) { + } catch (Exception | NoClassDefFoundError e) { } try { return cls.newInstance(); @@ -494,4 +485,45 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur public void parameterNameProviderClass(final Class<? extends ParameterNameProvider> clazz) { parameterNameProviderClass = clazz; } + + @Override + public ApacheValidatorConfiguration clockProvider(ClockProvider clockProvider) { + this.clockProvider = clockProvider; + return this; + } + + @Override + public ApacheValidatorConfiguration addValueExtractor(ValueExtractor<?> extractor) { + valueExtractors.add(extractor); + return this; + } + + @Override + public ClockProvider getDefaultClockProvider() { + return defaultClockProvider; + } + + @Override + public Set<ValueExtractor<?>> getValueExtractors() { + return Collections.unmodifiableSet(valueExtractors); + } + + @Override + public ClockProvider getClockProvider() { + if (beforeCdi) { + return defaultClockProvider; + } + if (clockProvider == defaultClockProvider && clockProviderClass != null) { + synchronized (this) { + if (clockProvider == defaultClockProvider && clockProviderClass != null) { + clockProvider = newInstance(clockProviderClass); + } + } + } + return clockProvider; + } + + protected void initializePropertyDefaults() { + properties.put(Properties.CONSTRAINTS_CACHE_SIZE, Integer.toString(50)); + } } http://git-wip-us.apache.org/repos/asf/bval/blob/05df7ee2/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java new file mode 100644 index 0000000..606e191 --- /dev/null +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.bval.jsr; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Set; + +import javax.validation.ConstraintViolation; +import javax.validation.ValidationException; +import javax.validation.executable.ExecutableValidator; +import javax.validation.metadata.BeanDescriptor; + +import org.apache.bval.jsr.job.ValidationJobFactory; +import org.apache.bval.util.Validate; +import org.apache.bval.util.reflection.Reflection; + +public class ValidatorImpl implements CascadingPropertyValidator, ExecutableValidator { + + private final ApacheFactoryContext validatorContext; + private final ValidationJobFactory validationJobFactory; + + ValidatorImpl(ApacheFactoryContext validatorContext) { + super(); + this.validatorContext = Validate.notNull(validatorContext, "validatorContext"); + this.validationJobFactory = new ValidationJobFactory(validatorContext); + } + + @Override + public BeanDescriptor getConstraintsForClass(Class<?> clazz) { + return validatorContext.getDescriptorManager().getBeanDescriptor(clazz); + } + + @Override + public <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) { + return validationJobFactory.validateBean(object, groups).getResults(); + } + + @Override + public <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, boolean cascade, + Class<?>... groups) { + return validationJobFactory.validateProperty(object, propertyName, groups).cascade(cascade).getResults(); + } + + @Override + public <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, + boolean cascade, Class<?>... groups) { + return validationJobFactory.validateValue(beanType, propertyName, value, groups).cascade(cascade).getResults(); + } + + @Override + public ExecutableValidator forExecutables() { + return this; + } + + @Override + public <T> Set<ConstraintViolation<T>> validateParameters(T object, Method method, Object[] parameterValues, + Class<?>... groups) { + return validationJobFactory.validateParameters(object, method, parameterValues, groups).getResults(); + } + + @Override + public <T> Set<ConstraintViolation<T>> validateReturnValue(T object, Method method, Object returnValue, + Class<?>... groups) { + return validationJobFactory.validateReturnValue(object, method, returnValue, groups).getResults(); + } + + @Override + public <T> Set<ConstraintViolation<T>> validateConstructorParameters(Constructor<? extends T> constructor, + Object[] parameterValues, Class<?>... groups) { + return validationJobFactory.<T> validateConstructorParameters(constructor, parameterValues, groups) + .getResults(); + } + + @Override + public <T> Set<ConstraintViolation<T>> validateConstructorReturnValue(Constructor<? extends T> constructor, + T createdObject, Class<?>... groups) { + return validationJobFactory.<T> validateConstructorReturnValue(constructor, createdObject, groups).getResults(); + } + + @Override + public <T> T unwrap(Class<T> type) { + // FIXME 2011-03-27 jw: + // This code is unsecure. + // It should allow only a fixed set of classes. + // Can't fix this because don't know which classes this method should support. + + if (type.isAssignableFrom(getClass())) { + @SuppressWarnings("unchecked") + final T result = (T) this; + return result; + } + if (!(type.isInterface() || Modifier.isAbstract(type.getModifiers()))) { + return newInstance(type); + } + try { + final Class<?> cls = Reflection.toClass(type.getName() + "Impl"); + if (type.isAssignableFrom(cls)) { + @SuppressWarnings("unchecked") + final Class<? extends T> implClass = (Class<? extends T>) cls; + return newInstance(implClass); + } + } catch (ClassNotFoundException e) { + } + throw new ValidationException("Type " + type + " not supported"); + } + + private <T> T newInstance(final Class<T> cls) { + final Constructor<T> cons = Reflection.getDeclaredConstructor(cls, ApacheFactoryContext.class); + if (cons == null) { + throw new ValidationException("Cannot instantiate " + cls); + } + final boolean mustUnset = Reflection.setAccessible(cons, true); + try { + return cons.newInstance(validatorContext); + } catch (final Exception ex) { + throw new ValidationException("Cannot instantiate " + cls, ex); + } finally { + if (mustUnset) { + Reflection.setAccessible(cons, false); + } + } + } +}
