This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-beanutils.git
The following commit(s) were added to refs/heads/master by this push:
new 54a3d04a Do not resolve suppressed mapped properties in
getPropertyDescriptor (#413)
54a3d04a is described below
commit 54a3d04a16508ecab241ad65243805982a4aec02
Author: Naveed Khan <[email protected]>
AuthorDate: Sat Jul 11 18:55:48 2026 +0000
Do not resolve suppressed mapped properties in getPropertyDescriptor (#413)
---
.../commons/beanutils2/PropertyUtilsBean.java | 24 ++++++++++++++++++++++
.../commons/beanutils2/PropertyUtilsTest.java | 21 +++++++++++++++++++
2 files changed, 45 insertions(+)
diff --git a/src/main/java/org/apache/commons/beanutils2/PropertyUtilsBean.java
b/src/main/java/org/apache/commons/beanutils2/PropertyUtilsBean.java
index 2e4d6ced..7232d88d 100644
--- a/src/main/java/org/apache/commons/beanutils2/PropertyUtilsBean.java
+++ b/src/main/java/org/apache/commons/beanutils2/PropertyUtilsBean.java
@@ -675,6 +675,13 @@ public class PropertyUtilsBean {
return result;
}
+ // A name removed by a SuppressPropertiesBeanIntrospector is absent
from data above, but the
+ // mapped-descriptor fallback below rebuilds descriptors straight from
the class methods and never
+ // consults the introspectors, so a suppressed mapped property would
still be resolved. Keep it hidden.
+ if (isPropertySuppressed(name)) {
+ return null;
+ }
+
Map mappedDescriptors = getMappedPropertyDescriptors(bean);
if (mappedDescriptors == null) {
mappedDescriptors = new ConcurrentHashMap<Class<?>, Map>();
@@ -698,6 +705,23 @@ public class PropertyUtilsBean {
return result;
}
+ /**
+ * 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.
+ *
+ * @param name The property name to test.
+ * @return {@code true} if the name is suppressed by an introspector.
+ */
+ private boolean isPropertySuppressed(final String name) {
+ for (final BeanIntrospector introspector : introspectors) {
+ if (introspector instanceof SuppressPropertiesBeanIntrospector
+ && ((SuppressPropertiesBeanIntrospector)
introspector).getSuppressedProperties().contains(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* <p>
* Retrieve the property descriptors for the specified class,
introspecting and caching them the first time a particular bean class is
encountered.
diff --git a/src/test/java/org/apache/commons/beanutils2/PropertyUtilsTest.java
b/src/test/java/org/apache/commons/beanutils2/PropertyUtilsTest.java
index b3b5d1bd..68338950 100644
--- a/src/test/java/org/apache/commons/beanutils2/PropertyUtilsTest.java
+++ b/src/test/java/org/apache/commons/beanutils2/PropertyUtilsTest.java
@@ -294,6 +294,27 @@ class PropertyUtilsTest {
PropertyUtils.removeBeanIntrospector(bi);
}
+ /**
+ * A mapped property removed by a {@link
SuppressPropertiesBeanIntrospector} must stay hidden. The mapped-descriptor
fallback in
+ * {@code getPropertyDescriptor} rebuilt the descriptor directly from the
class methods without consulting the introspectors, so a suppressed mapped
+ * property was still readable and writable through {@code name(key)}
access.
+ */
+ @Test
+ void testCustomIntrospectionSuppressedMappedProperty() throws Exception {
+ final PropertyUtilsBean pub = new PropertyUtilsBean();
+ pub.addBeanIntrospector(new
SuppressPropertiesBeanIntrospector(Arrays.asList("mappedProperty")));
+
+ assertNull(pub.getPropertyDescriptor(bean, "mappedProperty"),
"Suppressed mapped property should have no descriptor");
+ assertThrows(NoSuchMethodException.class, () -> pub.getProperty(bean,
"mappedProperty(First Key)"), "Suppressed mapped property must not be
readable");
+ assertThrows(NoSuchMethodException.class, () -> pub.setProperty(bean,
"mappedProperty(First Key)", "changed"),
+ "Suppressed mapped property must not be writable");
+ assertEquals("First Value", bean.getMappedProperty("First Key"),
"Suppressed mapped property must be unchanged");
+
+ // A mapped property that is not suppressed is still accessible.
+ final PropertyUtilsBean unsuppressed = new PropertyUtilsBean();
+ assertEquals("First Value", unsuppressed.getProperty(bean,
"mappedProperty(First Key)"), "Mapped property should be readable when not
suppressed");
+ }
+
/**
* Test the describe() method.
*/