Skip to content

Commit

Permalink
Uses Java Reflections instead BeanUtils to read property
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaszlenart committed Mar 4, 2022
1 parent 84164c4 commit c094052
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,24 @@
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")
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -150,7 +152,7 @@ public String getFieldExpressionValidatorField() {
}

public void setFieldExpressionValidatorField(
String fieldExpressionValidatorField) {
String fieldExpressionValidatorField) {
this.fieldExpressionValidatorField = fieldExpressionValidatorField;
}

Expand All @@ -163,8 +165,4 @@ public void setUrlValidatorField(String urlValidatorField) {
}
}

/**
* <!-- END SNIPPET: beanValidatationExample -->
*/


// <!-- END SNIPPET: beanValidationExample -->
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
*
* <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 -->
Expand Down
18 changes: 12 additions & 6 deletions plugins/bean-validation/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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
Expand Down Expand Up @@ -94,4 +100,4 @@

</dependencies>

</project>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -41,13 +44,23 @@ public void initialize(final FieldMatch constraintAnnotation) {

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;
}

}
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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. -->
Expand Down

0 comments on commit c094052

Please sign in to comment.