Skip to content

Commit

Permalink
BEANUTILS-541 - FluentPropertyBeanIntrospector caches corrupted write…
Browse files Browse the repository at this point in the history
…Method
  • Loading branch information
seregamorph committed Jan 10, 2021
1 parent 8d42aef commit 1552206
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 7 deletions.
4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,10 @@
<name>Bernhard Seebass</name>
<email></email>
</contributor>
<contributor>
<name>Sergey Chernov</name>
<email></email>
</contributor>
</contributors>

<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ private DefaultBeanIntrospector() {
*/
@Override
public void introspect(final IntrospectionContext icontext) {
BeanInfo beanInfo = null;
BeanInfo beanInfo;
try {
beanInfo = Introspector.getBeanInfo(icontext.getTargetClass());
} catch (final IntrospectionException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,13 @@ public void introspect(final IntrospectionContext icontext)
.getPropertyDescriptor(propertyName);
try {
if (pd == null) {
icontext.addPropertyDescriptor(createFluentPropertyDescritor(
m, propertyName));
icontext.addPropertyDescriptor(createFluentPropertyDescriptor(
m));
} else if (pd.getWriteMethod() == null) {
// We change statically cached PropertyDescriptor, it may affect
// other subclasses of targetClass supertype.
// See BEANUTILS-541 for more details.
clearDescriptorsCacheHierarchy(icontext.getTargetClass().getSuperclass());
pd.setWriteMethod(m);
}
} catch (final IntrospectionException e) {
Expand All @@ -152,6 +156,13 @@ public void introspect(final IntrospectionContext icontext)
}
}

private static void clearDescriptorsCacheHierarchy(Class<?> cls) {
if (cls != Object.class) {
Introspector.flushFromCaches(cls);
clearDescriptorsCacheHierarchy(cls.getSuperclass());
}
}

/**
* Derives the name of a property from the given set method.
*
Expand All @@ -169,12 +180,10 @@ private String propertyName(final Method m) {
* Creates a property descriptor for a fluent API property.
*
* @param m the set method for the fluent API property
* @param propertyName the name of the corresponding property
* @return the descriptor
* @throws IntrospectionException if an error occurs
*/
private PropertyDescriptor createFluentPropertyDescritor(final Method m,
final String propertyName) throws IntrospectionException {
private PropertyDescriptor createFluentPropertyDescriptor(final Method m) throws IntrospectionException {
return new PropertyDescriptor(propertyName(m), null, m);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* 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.commons.beanutils2.bugs;

import static org.junit.Assert.assertEquals;

import org.apache.commons.beanutils2.FluentPropertyBeanIntrospector;
import org.apache.commons.beanutils2.PropertyUtilsBean;
import org.junit.Test;

/**
* Fix BEANUTILS-541
*
* @see <a href="https://issues.apache.org/jira/browse/BEANUTILS-541">https://issues.apache.org/jira/browse/BEANUTILS-541</a>
*/
public class Jira541TestCase {

private static final String FIELD_NAME = "field";
private static final String FIELD_VALUE = "name";

@Test
public void testFluentBeanIntrospectorOnOverridenSetter() throws Exception {
PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
propertyUtilsBean.addBeanIntrospector(new FluentPropertyBeanIntrospector());

// note: we should setProperty first on SubTypeA (with overriden setter), then on subTypeB
// but not vice versa
SubTypeA subTypeA = new SubTypeA();
propertyUtilsBean.setProperty(subTypeA, FIELD_NAME, FIELD_VALUE);

SubTypeB subTypeB = new SubTypeB();
propertyUtilsBean.setProperty(subTypeB, FIELD_NAME, FIELD_VALUE);

assertEquals(FIELD_VALUE, subTypeA.getField());
assertEquals(FIELD_VALUE, subTypeB.getField());
}

public static class BaseType {

private String field;

public BaseType setField(String objectName) {
this.field = objectName;
return this;
}

public String getField() {
return field;
}
}

public static class SubTypeA extends BaseType {

@Override
public SubTypeA setField(String field) {
super.setField(field);
return this;
}
}

public static class SubTypeB extends BaseType {

}
}

0 comments on commit 1552206

Please sign in to comment.