Repository: wicket Updated Branches: refs/heads/wicket-6.x c3795bd0e -> f2f77d8fc
WICKET-5654 DefaultViolationTranslator should maybe use getMessage() Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/f2f77d8f Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/f2f77d8f Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/f2f77d8f Branch: refs/heads/wicket-6.x Commit: f2f77d8fcf7eeeac309010948ca36671cc51ac49 Parents: c3795bd Author: adelbene <[email protected]> Authored: Wed Aug 20 12:36:24 2014 +0200 Committer: adelbene <[email protected]> Committed: Wed Aug 20 15:56:51 2014 +0200 ---------------------------------------------------------------------- wicket-bean-validation/pom.xml | 6 + .../validation/DefaultViolationTranslator.java | 71 +++++++++--- .../validation/DefaultPropertyResolverTest.java | 113 ++++++++++++++++++- .../PasswordConstraintAnnotation.java | 45 ++++++++ .../customconstraint/PasswordValidator.java | 58 ++++++++++ 5 files changed, 272 insertions(+), 21 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/f2f77d8f/wicket-bean-validation/pom.xml ---------------------------------------------------------------------- diff --git a/wicket-bean-validation/pom.xml b/wicket-bean-validation/pom.xml index 1c239bb..8e8886f 100644 --- a/wicket-bean-validation/pom.xml +++ b/wicket-bean-validation/pom.xml @@ -31,6 +31,12 @@ <version>4.3.1.Final</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.glassfish.web</groupId> + <artifactId>el-impl</artifactId> + <version>2.2</version> + <scope>test</scope> + </dependency> </dependencies> <build> <plugins> http://git-wip-us.apache.org/repos/asf/wicket/blob/f2f77d8f/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/DefaultViolationTranslator.java ---------------------------------------------------------------------- diff --git a/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/DefaultViolationTranslator.java b/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/DefaultViolationTranslator.java index feec4f3..7b006aa 100644 --- a/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/DefaultViolationTranslator.java +++ b/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/DefaultViolationTranslator.java @@ -1,5 +1,8 @@ package org.apache.wicket.bean.validation; +import java.util.ArrayList; +import java.util.List; + import javax.validation.ConstraintViolation; import javax.validation.metadata.ConstraintDescriptor; @@ -24,37 +27,69 @@ public class DefaultViolationTranslator implements IViolationTranslator ValidationError error = new ValidationError(); error.setMessage(violation.getMessage()); - String messageKey = getMessageKey(desc); - if (messageKey != null) - { - if (violation.getInvalidValue() != null) - { - error.addKey(messageKey + "." + - violation.getInvalidValue().getClass().getSimpleName()); - } - error.addKey(messageKey); - } + List<String> messages = getViolationMessages(violation, desc); + addErrorKeys(error, violation.getInvalidValue(), messages); for (String key : desc.getAttributes().keySet()) { error.setVariable(key, desc.getAttributes().get(key)); } + return error; } - private String getMessageKey(ConstraintDescriptor<?> desc) + private List<String> getViolationMessages(ConstraintViolation<?> violation, + ConstraintDescriptor<?> desc) { - final Object val = desc.getAttributes().get("message"); - if (val != null) + String defaultMessage = (String)desc.getAttributes().get("message"); + String violationMessage = violation.getMessage(); + String violationMessageTemplate = violation.getMessageTemplate(); + List<String> messages = new ArrayList<String>(); + + //violation message is considered only if it is different from + //the interpolated message + if (!Strings.isEqual(violationMessage, violationMessageTemplate)) { - String str = val.toString(); - if (!Strings.isEmpty(str) && str.startsWith("{") && str.endsWith("}")) + messages.add(violationMessageTemplate); + } + + messages.add(violationMessage); + + //the default message is considered only if it is different from + //the violation message template + if (!Strings.isEqual(defaultMessage, violationMessageTemplate)) + { + messages.add(defaultMessage); + } + + return messages; + } + + private void addErrorKeys(ValidationError error, Object invalidValue, List<String> messages) + { + for (String message : messages) + { + String messageKey = getMessageKey(message); + + if (messageKey != null) { - return str.substring(1, str.length() - 1); + if (invalidValue != null) + { + error.addKey(messageKey + "." + invalidValue.getClass().getSimpleName()); + } + + error.addKey(messageKey); } } - return null; } - + private String getMessageKey(String message) + { + if (!Strings.isEmpty(message) && message.startsWith("{") && message.endsWith("}")) + { + return message.substring(1, message.length() - 1); + } + + return null; + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/wicket/blob/f2f77d8f/wicket-bean-validation/src/test/java/org/apache/wicket/bean/validation/DefaultPropertyResolverTest.java ---------------------------------------------------------------------- diff --git a/wicket-bean-validation/src/test/java/org/apache/wicket/bean/validation/DefaultPropertyResolverTest.java b/wicket-bean-validation/src/test/java/org/apache/wicket/bean/validation/DefaultPropertyResolverTest.java index 99ad65d..56eebb1 100644 --- a/wicket-bean-validation/src/test/java/org/apache/wicket/bean/validation/DefaultPropertyResolverTest.java +++ b/wicket-bean-validation/src/test/java/org/apache/wicket/bean/validation/DefaultPropertyResolverTest.java @@ -16,12 +16,28 @@ */ package org.apache.wicket.bean.validation; -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; - +import static org.apache.wicket.bean.validation.customconstraint.PasswordConstraintAnnotation.CUSTOM_BUNDLE_KEY; +import static org.apache.wicket.bean.validation.customconstraint.PasswordConstraintAnnotation.DEFAULT_BUNDLE_KEY; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.Set; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; + +import org.apache.wicket.bean.validation.customconstraint.PasswordConstraintAnnotation; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.util.tester.WicketTesterScope; +import org.apache.wicket.validation.ValidationError; import org.junit.Rule; import org.junit.Test; @@ -116,6 +132,76 @@ public class DefaultPropertyResolverTest assertThat(property.getOwner().getName(), is(Bean4.class.getName())); } + /** + * Test custom bundle mechanism of jsr 303 + * + * https://issues.apache.org/jira/browse/WICKET-5654 + * + * @throws Exception + */ + @Test + public void testBundleKeysResolution() throws Exception + { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + Validator validator = factory.getValidator(); + DefaultViolationTranslator translator = new DefaultViolationTranslator(); + + // test with a too short password + BeanWithPassword bean = new BeanWithPassword("short"); + + Set<ConstraintViolation<BeanWithPassword>> constraintViolations = validator.validate(bean); + assertEquals(1, constraintViolations.size()); + + @SuppressWarnings("unchecked") + ConstraintViolation<BeanWithPassword> shortViolation = (ConstraintViolation<BeanWithPassword>)constraintViolations + .toArray()[0]; + + ValidationError error = translator.convert(shortViolation); + + checkErrorBundleKeys(error, DEFAULT_BUNDLE_KEY + ".String", DEFAULT_BUNDLE_KEY); + + // test with a password containing non-word chars + bean.setPassword("notWord&%$£"); + + constraintViolations = validator.validate(bean); + assertEquals(1, constraintViolations.size()); + + @SuppressWarnings("unchecked") + ConstraintViolation<BeanWithPassword> nonWordviolation = (ConstraintViolation<BeanWithPassword>)constraintViolations.toArray()[0]; + + error = translator.convert(nonWordviolation); + + checkErrorBundleKeys(error, CUSTOM_BUNDLE_KEY + ".String", CUSTOM_BUNDLE_KEY, + DEFAULT_BUNDLE_KEY + ".String", DEFAULT_BUNDLE_KEY); + + // test with a valid password + bean.setPassword("aValidPassword1234"); + + constraintViolations = validator.validate(bean); + assertEquals(0, constraintViolations.size()); + } + + /** + * Checks that validation error has the expected keys as bundle keys, in the order they are + * specified in {@code expectedKeys}. + * + * @param error + * @param expectedKeys + */ + private void checkErrorBundleKeys(ValidationError error, String... expectedKeys) + { + List<String> keys = error.getKeys(); + + assertEquals("The expected number for bundle keys is '" + expectedKeys.length + + "' but we have '" + keys.size() + "'", expectedKeys.length, keys.size()); + + for (int i = 0; i < expectedKeys.length; i++) + { + String expectedKey = expectedKeys[i]; + + assertTrue(keys.get(i).equals(expectedKey)); + } + } public static class Bean3 { @@ -143,4 +229,25 @@ public class DefaultPropertyResolverTest return "foo4"; } } + + public static class BeanWithPassword + { + @PasswordConstraintAnnotation + private String password; + + public BeanWithPassword(String password) + { + this.password = password; + } + + public String getPassword() + { + return password; + } + + public void setPassword(String password) + { + this.password = password; + } + } } http://git-wip-us.apache.org/repos/asf/wicket/blob/f2f77d8f/wicket-bean-validation/src/test/java/org/apache/wicket/bean/validation/customconstraint/PasswordConstraintAnnotation.java ---------------------------------------------------------------------- diff --git a/wicket-bean-validation/src/test/java/org/apache/wicket/bean/validation/customconstraint/PasswordConstraintAnnotation.java b/wicket-bean-validation/src/test/java/org/apache/wicket/bean/validation/customconstraint/PasswordConstraintAnnotation.java new file mode 100644 index 0000000..73f0ab1 --- /dev/null +++ b/wicket-bean-validation/src/test/java/org/apache/wicket/bean/validation/customconstraint/PasswordConstraintAnnotation.java @@ -0,0 +1,45 @@ +/* + * 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.wicket.bean.validation.customconstraint; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +@Target({ METHOD, FIELD, ANNOTATION_TYPE }) +@Retention(RUNTIME) +@Constraint(validatedBy = PasswordValidator.class) +@Documented +public @interface PasswordConstraintAnnotation +{ + public static final String DEFAULT_BUNDLE_KEY = "default.bundle.key"; + public static final String CUSTOM_BUNDLE_KEY = "custom.bundle.key"; + + String message() default "{" + DEFAULT_BUNDLE_KEY +"}"; + + Class<?>[] groups() default { }; + + Class<? extends Payload>[] payload() default { }; +} http://git-wip-us.apache.org/repos/asf/wicket/blob/f2f77d8f/wicket-bean-validation/src/test/java/org/apache/wicket/bean/validation/customconstraint/PasswordValidator.java ---------------------------------------------------------------------- diff --git a/wicket-bean-validation/src/test/java/org/apache/wicket/bean/validation/customconstraint/PasswordValidator.java b/wicket-bean-validation/src/test/java/org/apache/wicket/bean/validation/customconstraint/PasswordValidator.java new file mode 100644 index 0000000..a319953 --- /dev/null +++ b/wicket-bean-validation/src/test/java/org/apache/wicket/bean/validation/customconstraint/PasswordValidator.java @@ -0,0 +1,58 @@ +/* + * 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.wicket.bean.validation.customconstraint; + +import java.util.regex.Matcher; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +import org.apache.wicket.util.parse.metapattern.MetaPattern; +import org.apache.wicket.util.string.Strings; + +public class PasswordValidator implements ConstraintValidator<PasswordConstraintAnnotation, String> +{ + + @Override + public void initialize(PasswordConstraintAnnotation constraintAnnotation) + { + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) + { + // password must be at least 8 chars long. + if (Strings.isEmpty(value) || value.length() < 8) + { + return false; + } + + Matcher matcher = MetaPattern.NON_WORD.matcher(value); + + // password must not contain non-word characters. + if (matcher.find()) + { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate("{" + + PasswordConstraintAnnotation.CUSTOM_BUNDLE_KEY + "}").addConstraintViolation(); + return false; + } + + return true; + } + +}
