Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ private Class<?> reLoadClass(final String name) {
*
* @param s The property name
*/
private static String capitalizePropertyName(final String s) {
static String capitalizePropertyName(final String s) {
if (s.isEmpty()) {
return s;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1068,15 +1068,21 @@ private Object invokeMethod(final Method method, final Object bean, final Object
/**
* Tests whether a property name has been removed by a registered {@link SuppressPropertiesBeanIntrospector}. The mapped-descriptor fallback in
* {@link #getPropertyDescriptor(Object, String)} bypasses the introspection pipeline, so suppressed mapped property names must be filtered explicitly.
* {@link MappedPropertyDescriptor} derives its accessor names from the capitalized property name, so names differing only in the case of their first
* character resolve the same accessors and are compared on that capitalized form here.
*
* @param name The property name to test.
* @return {@code true} if the name is suppressed by an introspector.
*/
private boolean isPropertySuppressed(final String name) {
final String base = MappedPropertyDescriptor.capitalizePropertyName(name);
for (final BeanIntrospector introspector : introspectors) {
if (introspector instanceof SuppressPropertiesBeanIntrospector
&& ((SuppressPropertiesBeanIntrospector) introspector).getSuppressedProperties().contains(name)) {
return true;
if (introspector instanceof SuppressPropertiesBeanIntrospector) {
for (final String suppressed : ((SuppressPropertiesBeanIntrospector) introspector).getSuppressedProperties()) {
if (base.equals(MappedPropertyDescriptor.capitalizePropertyName(suppressed))) {
return true;
}
}
}
}
return false;
Expand Down
17 changes: 17 additions & 0 deletions src/test/java/org/apache/commons/beanutils2/PropertyUtilsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,23 @@ void testCustomIntrospectionSuppressedMappedProperty() throws Exception {
assertEquals("First Value", unsuppressed.getProperty(bean, "mappedProperty(First Key)"), "Mapped property should be readable when not suppressed");
}

/**
* {@link MappedPropertyDescriptor} capitalizes the first character of the property name to build the accessor names, so {@code MappedProperty(key)}
* resolves the same {@code getMappedProperty}/{@code setMappedProperty} pair as {@code mappedProperty(key)} and must be suppressed with it.
*/
@Test
void testCustomIntrospectionSuppressedMappedPropertyCaseVariant() throws Exception {
final PropertyUtilsBean pub = new PropertyUtilsBean();
pub.addBeanIntrospector(new SuppressPropertiesBeanIntrospector(Arrays.asList("mappedProperty")));

assertNull(pub.getPropertyDescriptor(bean, "MappedProperty"), "Case variant of a suppressed mapped property should have no descriptor");
assertThrows(NoSuchMethodException.class, () -> pub.getProperty(bean, "MappedProperty(First Key)"),
"Case variant of a suppressed mapped property must not be readable");
assertThrows(NoSuchMethodException.class, () -> pub.setProperty(bean, "MappedProperty(First Key)", "changed"),
"Case variant of a suppressed mapped property must not be writable");
assertEquals("First Value", bean.getMappedProperty("First Key"), "Suppressed mapped property must be unchanged");
}

/**
* Test the describe() method.
*/
Expand Down
Loading