This is an automated email from the ASF dual-hosted git repository. adelbene pushed a commit to branch WICKET-6662 in repository https://gitbox.apache.org/repos/asf/wicket.git
commit 8340b1009f84292fbec3523de79aca1751883a81 Author: Sven Meier <[email protected]> AuthorDate: Fri Apr 19 09:56:39 2019 +0200 WICKET-6656 allow bean validation to handle required annotations and updated dependencies; this closes #353 --- .../validation/BeanValidationConfiguration.java | 44 ++++++++- .../bean/validation/BeanValidationContext.java | 14 +++ .../wicket/bean/validation/PropertyValidator.java | 110 +++++++-------------- wicket-examples/pom.xml | 6 -- .../constraint/ValidPasswordValidator.java | 6 +- 5 files changed, 97 insertions(+), 83 deletions(-) diff --git a/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/BeanValidationConfiguration.java b/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/BeanValidationConfiguration.java index d705a63..7971c84 100644 --- a/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/BeanValidationConfiguration.java +++ b/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/BeanValidationConfiguration.java @@ -1,6 +1,8 @@ package org.apache.wicket.bean.validation; import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -8,7 +10,10 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Supplier; import javax.validation.Validator; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; +import javax.validation.metadata.ConstraintDescriptor; import org.apache.wicket.Application; import org.apache.wicket.MetaDataKey; @@ -27,6 +32,28 @@ public class BeanValidationConfiguration implements BeanValidationContext { }; + /** + * Default list of annotations that make a component required. + */ + static final List<Class<? extends Annotation>> REQUIRED_ANNOTATIONS; + static + { + List<Class<? extends Annotation>> tmp = new ArrayList<>(); + tmp.add(NotNull.class); + try + { + tmp.add(Class.forName("javax.validation.constraints.NotBlank") + .asSubclass(Annotation.class)); + tmp.add(Class.forName("javax.validation.constraints.NotEmpty") + .asSubclass(Annotation.class)); + } + catch (ClassNotFoundException e) + { + // ignore exception, we are using bean validation 1.1 + } + REQUIRED_ANNOTATIONS = Collections.unmodifiableList(tmp); + } + private Supplier<Validator> validatorProvider = new DefaultValidatorProvider(); private IViolationTranslator violationTranslator = new DefaultViolationTranslator(); @@ -61,7 +88,6 @@ public class BeanValidationConfiguration implements BeanValidationContext return this; } - @Override @SuppressWarnings("unchecked") public <T extends Annotation> ITagModifier<T> getTagModifier(Class<T> annotationType) @@ -131,8 +157,8 @@ public class BeanValidationConfiguration implements BeanValidationContext * Registers a violation translator * * @param violationTranslator - * A violation translator that will convert {@link javax.validation.ConstraintViolation}s - * into Wicket's {@link org.apache.wicket.validation.ValidationError}s + * A violation translator that will convert {@link javax.validation.ConstraintViolation}s into Wicket's + * {@link org.apache.wicket.validation.ValidationError}s */ public void setViolationTranslator(IViolationTranslator violationTranslator) { @@ -171,4 +197,16 @@ public class BeanValidationConfiguration implements BeanValidationContext } return null; } + + /** + * By default {@link NotNull} and {@link NotEmpty} constraints make a component required. + * + * @param constraint + * constraint + */ + @Override + public boolean isRequiredConstraint(ConstraintDescriptor<?> constraint) + { + return REQUIRED_ANNOTATIONS.contains(constraint.getAnnotation().annotationType()); + } } diff --git a/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/BeanValidationContext.java b/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/BeanValidationContext.java index dd5c4a0..8f1f8b9 100644 --- a/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/BeanValidationContext.java +++ b/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/BeanValidationContext.java @@ -3,6 +3,7 @@ package org.apache.wicket.bean.validation; import java.lang.annotation.Annotation; import javax.validation.Validator; +import javax.validation.metadata.ConstraintDescriptor; import org.apache.wicket.markup.html.form.FormComponent; @@ -36,6 +37,19 @@ public interface BeanValidationContext extends IPropertyResolver */ IViolationTranslator getViolationTranslator(); + /** + * Resolve the property for a component. + * + * @param component component + */ @Override Property resolveProperty(FormComponent<?> component); + + /** + * Does the given constraint make a component required. + * + * @param constraint constraint + * @return <code>true</code> if required + */ + boolean isRequiredConstraint(ConstraintDescriptor<?> constraint); } \ No newline at end of file diff --git a/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/PropertyValidator.java b/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/PropertyValidator.java index 9cee8f8..437c04a 100644 --- a/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/PropertyValidator.java +++ b/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/PropertyValidator.java @@ -1,17 +1,12 @@ package org.apache.wicket.bean.validation; -import java.lang.annotation.Annotation; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; import java.util.Iterator; -import java.util.List; import java.util.Set; import javax.validation.ConstraintViolation; import javax.validation.Validator; -import javax.validation.constraints.NotNull; import javax.validation.groups.Default; import javax.validation.metadata.ConstraintDescriptor; @@ -21,8 +16,8 @@ import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.html.form.FormComponent; import org.apache.wicket.model.IModel; import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.validation.INullAcceptingValidator; import org.apache.wicket.validation.IValidatable; -import org.apache.wicket.validation.IValidator; /** * Validator that delegates to the bean validation framework. The integration has to be first @@ -57,33 +52,16 @@ import org.apache.wicket.validation.IValidator; * * @param <T> */ -public class PropertyValidator<T> extends Behavior implements IValidator<T> +public class PropertyValidator<T> extends Behavior implements INullAcceptingValidator<T> { private static final Class<?>[] EMPTY = new Class<?>[0]; - private static final List<Class<? extends Annotation>> NOT_NULL_ANNOTATIONS; - static - { - List<Class<? extends Annotation>> tmp = new ArrayList<>(); - tmp.add(NotNull.class); - try - { - tmp.add(Class.forName("javax.validation.constraints.NotBlank") - .asSubclass(Annotation.class)); - tmp.add(Class.forName("javax.validation.constraints.NotEmpty") - .asSubclass(Annotation.class)); - } - catch (ClassNotFoundException e) - { - // ignore exception, we are using bean validation 1.1 - } - NOT_NULL_ANNOTATIONS = Collections.unmodifiableList(tmp); - } private FormComponent<T> component; // the trailing underscore means that these members should not be used // directly. ALWAYS use the respective getter instead. private Property property_; + private final IModel<Class<?>[]> groups_; /** @@ -114,14 +92,17 @@ public class PropertyValidator<T> extends Behavior implements IValidator<T> /** * To support debugging, trying to provide useful information where possible + * * @return */ - private String createUnresolvablePropertyMessage(FormComponent<T> component) { + private String createUnresolvablePropertyMessage(FormComponent<T> component) + { String baseMessage = "Could not resolve Bean Property from component: " + component - + ". (Hints:) Possible causes are a typo in the PropertyExpression, a null reference or a model that does not work in combination with a " - + IPropertyResolver.class.getSimpleName() + "."; - IModel<?> model = ValidationModelResolver.resolvePropertyModelFrom(component); - if (model != null) { + + ". (Hints:) Possible causes are a typo in the PropertyExpression, a null reference or a model that does not work in combination with a " + + IPropertyResolver.class.getSimpleName() + "."; + IModel<?> model = ValidationModelResolver.resolvePropertyModelFrom(component); + if (model != null) + { baseMessage += " Model : " + model; } return baseMessage; @@ -157,15 +138,14 @@ public class PropertyValidator<T> extends Behavior implements IValidator<T> if (this.component != null) { throw new IllegalStateException( // - "This validator has already been added to component: " - + this.component + "This validator has already been added to component: " + this.component + ". This validator does not support reusing instances, please create a new one"); } if (!(component instanceof FormComponent)) { - throw new IllegalStateException(getClass().getSimpleName() - + " can only be added to FormComponents"); + throw new IllegalStateException( + getClass().getSimpleName() + " can only be added to FormComponents"); } // TODO add a validation key that appends the type so we can have @@ -187,6 +167,7 @@ public class PropertyValidator<T> extends Behavior implements IValidator<T> // that model object is accessible (i.e. component is already added // in a page). requiredFlagSet = true; + if (isRequired()) { this.component.setRequired(true); @@ -204,55 +185,38 @@ public class PropertyValidator<T> extends Behavior implements IValidator<T> } } - private List<ConstraintDescriptor<?>> findNotNullConstraints(List<Class<? extends Annotation>> notNullAnnotationTypes) + /** + * Should this property make the owning component required. + * + * @return <code>true</code> if required + * + * @see BeanValidationContext#isRequiredConstraint(ConstraintDescriptor) + */ + protected boolean isRequired() { BeanValidationContext config = BeanValidationConfiguration.get(); - Validator validator = config.getValidator(); - Property property = getProperty(); - - List<ConstraintDescriptor<?>> constraints = new ArrayList<>(); - Iterator<ConstraintDescriptor<?>> it = new ConstraintIterator(validator, property); + HashSet<Class<?>> groups = new HashSet<Class<?>>(Arrays.asList(getGroups())); + Iterator<ConstraintDescriptor<?>> it = new ConstraintIterator(config.getValidator(), getProperty()); while (it.hasNext()) { - ConstraintDescriptor<?> desc = it.next(); - Annotation annotation = desc.getAnnotation(); - Class<? extends Annotation> annotationType = annotation.annotationType(); - if (notNullAnnotationTypes.contains(annotationType)) - { - constraints.add(desc); - } - } - - return constraints; - } - - boolean isRequired() - { - List<ConstraintDescriptor<?>> constraints = findNotNullConstraints(NOT_NULL_ANNOTATIONS); - - if (constraints.isEmpty()) - { - return false; - } - - Set<Class<?>> validatorGroups = new HashSet<>(); - validatorGroups.addAll(Arrays.asList(getGroups())); - - for (ConstraintDescriptor<?> constraint : constraints) - { - if (canApplyToDefaultGroup(constraint) && validatorGroups.isEmpty()) - { - return true; - } - - for (Class<?> constraintGroup : constraint.getGroups()) + ConstraintDescriptor<?> constraint = it.next(); + + if (config.isRequiredConstraint(constraint)) { - if (validatorGroups.contains(constraintGroup)) + if (canApplyToDefaultGroup(constraint) && groups.size() == 0) { return true; } + + for (Class<?> constraintGroup : constraint.getGroups()) + { + if (groups.contains(constraintGroup)) + { + return true; + } + } } } diff --git a/wicket-examples/pom.xml b/wicket-examples/pom.xml index faf9962..65e6bfd 100644 --- a/wicket-examples/pom.xml +++ b/wicket-examples/pom.xml @@ -56,11 +56,6 @@ <groupId>org.codelibs</groupId> <artifactId>jhighlight</artifactId> <version>1.0.3</version> - - </dependency> - <dependency> - <groupId>org.hibernate.validator</groupId> - <artifactId>hibernate-validator</artifactId> </dependency> </dependencies> </dependencyManagement> @@ -145,7 +140,6 @@ <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> - <version>6.0.13.Final</version> <scope>compile</scope> </dependency> <dependency> diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/bean/validation/constraint/ValidPasswordValidator.java b/wicket-examples/src/main/java/org/apache/wicket/examples/bean/validation/constraint/ValidPasswordValidator.java index 1b68dd3..f392501 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/bean/validation/constraint/ValidPasswordValidator.java +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/bean/validation/constraint/ValidPasswordValidator.java @@ -38,7 +38,11 @@ public class ValidPasswordValidator implements ConstraintValidator<ValidPassword { boolean validationResult = true; - if (!CONTENT.matcher(value).matches()) + if (value == null) + { + validationResult = false; + } + else if (!CONTENT.matcher(value).matches()) { validationResult = false; }
