Uses Java Reflections instead BeanUtils to read property

This commit is contained in:
Lukasz Lenart
2022-03-04 12:52:33 +01:00
parent 84164c422e
commit c094052969
6 changed files with 130 additions and 28 deletions
@@ -27,22 +27,24 @@ import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.interceptor.validation.SkipValidation;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.ScriptAssert;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import java.util.Date;
/**
* <!-- START SNIPPET: beanValidatationExample -->
*/
// <!-- START SNIPPET: beanValidationExample -->
@Namespace("/bean-validation")
@ParentPackage("bean-validation")
@Action(results = {
@Result(name = "input", location = "bean-validation.jsp"),
@Result(name = "success", location = "/WEB-INF/validation/successFieldValidatorsExample.jsp")
@Result(name = "input", location = "bean-validation.jsp"),
@Result(name = "success", location = "/WEB-INF/validation/successFieldValidatorsExample.jsp")
})
@FieldMatch(first = "fieldExpressionValidatorField", second = "requiredValidatorField", message = "requiredValidatorField and fieldExpressionValidatorField are not matching")
@ScriptAssert(lang = "javascript", script = "_this.dateValidatorField != null && _this.dateValidatorField.before(new java.util.Date())", message = "Date need to before now")
@@ -82,10 +84,10 @@ public class BeanValidationExampleAction extends ActionSupport {
private String fieldExpressionValidatorField = null;
@Action(value = "bean-validation", results = {
@Result(name = "success", location = "bean-validation.jsp")
@Result(name = "success", location = "bean-validation.jsp")
})
@SkipValidation
public String beanValidation(){
public String beanValidation() {
return SUCCESS;
}
@@ -150,7 +152,7 @@ public class BeanValidationExampleAction extends ActionSupport {
}
public void setFieldExpressionValidatorField(
String fieldExpressionValidatorField) {
String fieldExpressionValidatorField) {
this.fieldExpressionValidatorField = fieldExpressionValidatorField;
}
@@ -163,8 +165,4 @@ public class BeanValidationExampleAction extends ActionSupport {
}
}
/**
* <!-- END SNIPPET: beanValidatationExample -->
*/
// <!-- END SNIPPET: beanValidationExample -->
@@ -38,7 +38,8 @@ import java.lang.annotation.Target;
*
* <p>
* Application wide conversion:<br>
* The conversion rules will be assembled within the <code>xwork-conversion.properties</code> file within the classpath root.
* The conversion rules will be assembled within the <code>struts-conversion.properties</code> or
* <code>xwork-conversion.properties</code> (deprecated) file within the classpath root.
* Set type to: <code>type = ConversionType.APPLICATION</code>
* </p>
* <!-- END SNIPPET: description -->
+12 -6
View File
@@ -44,11 +44,6 @@
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
@@ -60,6 +55,17 @@
<artifactId>javax.el</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<!-- this library is excluded in the parent pom as it clashes with Easymock dependencies -->
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>3.2</version>
</dependency>
<!--
The Java EE API modules listed below are all marked @Deprecated(forRemoval=true), because they are scheduled
@@ -94,4 +100,4 @@
</dependencies>
</project>
</project>
@@ -20,17 +20,20 @@
*/
package org.apache.struts.beanvalidation.constraints.impl;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts.beanvalidation.constraints.FieldMatch;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
public class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object> {
private static final Logger LOG = LogManager.getLogger(FieldMatchValidator.class);
private String firstFieldName;
private String secondFieldName;
@@ -41,13 +44,23 @@ public class FieldMatchValidator implements ConstraintValidator<FieldMatch, Obje
public boolean isValid(final Object value, final ConstraintValidatorContext context) {
try {
final Object firstObj = PropertyUtils.getProperty(value, this.firstFieldName);
final Object secondObj = PropertyUtils.getProperty(value, this.secondFieldName);
final Object firstObj = readPropertyValue(value, this.firstFieldName);
final Object secondObj = readPropertyValue(value, this.secondFieldName);
return firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
} catch (final Exception ex) {
LOG.info("Error while getting values from object", ex);
return false;
}
}
private Object readPropertyValue(Object bean, String propertyName) throws Exception {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {
if (propertyName.equals(descriptor.getName())) {
return descriptor.getReadMethod().invoke(bean);
}
}
return null;
}
}
@@ -0,0 +1,84 @@
/*
* 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.struts.beanvalidation.constraints.impl;
import org.apache.struts.beanvalidation.constraints.FieldMatch;
import org.junit.Test;
import org.mockito.Mockito;
import javax.validation.ConstraintValidatorContext;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class FieldMatchValidatorTest {
@Test
public void matchingFields() {
// given
FieldMatchValidator validator = new FieldMatchValidator();
validator.initialize(FieldMatchTestBean.class.getAnnotation(FieldMatch.class));
ConstraintValidatorContext context = Mockito.mock(ConstraintValidatorContext.class);
// when
FieldMatchTestBean bean = new FieldMatchTestBean("12345678", "12345678");
boolean valid = validator.isValid(bean, context);
// then
assertTrue(valid);
}
@Test
public void notMatchingFields() {
// given
FieldMatchValidator validator = new FieldMatchValidator();
validator.initialize(FieldMatchTestBean.class.getAnnotation(FieldMatch.class));
ConstraintValidatorContext context = Mockito.mock(ConstraintValidatorContext.class);
// when
FieldMatchTestBean bean = new FieldMatchTestBean("12345678", "87654321");
boolean valid = validator.isValid(bean, context);
// then
assertFalse(valid);
}
@FieldMatch(first = "password", second = "repeatPassword")
public static class FieldMatchTestBean {
String password;
String repeatPassword;
public FieldMatchTestBean(String password, String repeatPassword) {
this.password = password;
this.repeatPassword = repeatPassword;
}
public String getPassword() {
return password;
}
public String getRepeatPassword() {
return repeatPassword;
}
}
}
+1 -1
View File
@@ -1075,7 +1075,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.3.3</version>
<version>4.3.1</version>
<exclusions>
<!-- The mockito-core artifact and easymock artifact use different versions of objenesis (2.6 vs 3.1).
Excluding the older version here to pass enforcer. When next upgrading mockito-core, confirm whether this exclusion is still required. -->