This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 2541dd7430 JUNEAU-248 BeanMap containsKey() and keySet().contains()
don't match
2541dd7430 is described below
commit 2541dd74300878e02cd489a08d992673685faed8
Author: James Bognar <[email protected]>
AuthorDate: Mon Oct 13 15:56:47 2025 -0400
JUNEAU-248 BeanMap containsKey() and keySet().contains() don't match
---
.../apache/juneau/common/utils/StringUtils.java | 10 ++++++--
.../src/main/java/org/apache/juneau/BeanMap.java | 13 ++++++++--
.../java/org/apache/juneau/BeanMapErrors_Test.java | 29 +++++++++++-----------
3 files changed, 34 insertions(+), 18 deletions(-)
diff --git
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
index e47909c759..23ae2f7dbb 100644
---
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
+++
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
@@ -1575,10 +1575,16 @@ public class StringUtils {
var key = s.substring(x+1, i);
key = (hasInternalVar ?
replaceVars(key, m) : key);
hasInternalVar = false;
- if (! m.containsKey(key))
+ // JUNEAU-248: Check if key
exists in map by attempting to get it
+ // For regular maps: use
containsKey() OR get() != null check
+ // For BeanMaps: get() returns
non-null for accessible properties (including hidden ones)
+ var val = m.get(key);
+ // Check if key actually
exists: either containsKey is true, or val is non-null
+ // This handles both regular
maps and BeanMaps correctly
+ var keyExists =
m.containsKey(key) || val != null;
+ if (! keyExists)
out.append('{').append(key).append('}');
else {
- var val = m.get(key);
if (val == null)
val = "";
var v = val.toString();
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java
index abc1e6fb3b..0a0886889e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java
@@ -261,9 +261,18 @@ public class BeanMap<T> extends AbstractMap<String,Object>
implements Delegate<T
@Override /* Map */
public boolean containsKey(Object property) {
- if (getPropertyMeta(emptyIfNull(property)) != null)
+ // JUNEAU-248: Match the behavior of keySet() - only check
properties map, not hiddenProperties
+ String key = emptyIfNull(property);
+ if (meta.properties.containsKey(key) && ! "*".equals(key))
return true;
- return super.containsKey(property);
+ if (meta.dynaProperty != null) {
+ try {
+ return
meta.dynaProperty.getDynaMap(bean).containsKey(key);
+ } catch (Exception e) {
+ throw new BeanRuntimeException(e);
+ }
+ }
+ return false;
}
/**
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/BeanMapErrors_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/BeanMapErrors_Test.java
index ebbd2b61c5..08342ed08c 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/BeanMapErrors_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/BeanMapErrors_Test.java
@@ -30,15 +30,15 @@ class BeanMapErrors_Test extends TestBase {
//-----------------------------------------------------------------------------------------------------------------
// @Beanp(name) on method not in @Bean(properties)
- // Shouldn't be found in keySet()/entrySet() but should be found in
containsKey()/get()
+ // JUNEAU-248: Shouldn't be found in keySet()/entrySet()/containsKey()
but should be accessible via get()/put()
//-----------------------------------------------------------------------------------------------------------------
@Test void beanPropertyMethodNotInBeanProperties() {
var bc = BeanContext.DEFAULT;
var bm = bc.newBeanMap(A1.class);
- assertTrue(bm.containsKey("f2"));
- assertEquals(-1, bm.get("f2"));
- bm.put("f2", -2);
+ assertFalse(bm.containsKey("f2")); // JUNEAU-248: Now
consistent with keySet()
+ assertEquals(-1, bm.get("f2")); // But get() still works
+ bm.put("f2", -2); // And put() still works
assertEquals(-2, bm.get("f2"));
assertFalse(bm.keySet().contains("f2"));
assertFalse(bm.entrySet().stream().map(Entry::getKey).toList().contains("f2"));
@@ -57,9 +57,9 @@ class BeanMapErrors_Test extends TestBase {
var bc =
BeanContext.create().applyAnnotations(B1Config.class).build();
var bm = bc.newBeanMap(B1.class);
- assertTrue(bm.containsKey("f2"));
- assertEquals(-1, bm.get("f2"));
- bm.put("f2", -2);
+ assertFalse(bm.containsKey("f2")); // JUNEAU-248: Now
consistent with keySet()
+ assertEquals(-1, bm.get("f2")); // But get() still works
+ bm.put("f2", -2); // And put() still works
assertEquals(-2, bm.get("f2"));
assertFalse(bm.keySet().contains("f2"));
assertFalse(bm.entrySet().stream().map(Entry::getKey).toList().contains("f2"));
@@ -81,14 +81,15 @@ class BeanMapErrors_Test extends TestBase {
//-----------------------------------------------------------------------------------------------------------------
// @Beanp(name) on field not in @Bean(properties)
+ // JUNEAU-248: Shouldn't be found in keySet()/entrySet()/containsKey()
but should be accessible via get()/put()
//-----------------------------------------------------------------------------------------------------------------
@Test void beanPropertyFieldNotInBeanProperties() {
var bc = BeanContext.DEFAULT;
var bm = bc.newBeanMap(A2.class);
- assertTrue(bm.containsKey("f2"));
- assertEquals(-1, bm.get("f2"));
- bm.put("f2", -2);
+ assertFalse(bm.containsKey("f2")); // JUNEAU-248: Now
consistent with keySet()
+ assertEquals(-1, bm.get("f2")); // But get() still works
+ bm.put("f2", -2); // And put() still works
assertEquals(-2, bm.get("f2"));
assertFalse(bm.keySet().contains("f2"));
assertFalse(bm.entrySet().stream().map(Entry::getKey).toList().contains("f2"));
@@ -102,13 +103,13 @@ class BeanMapErrors_Test extends TestBase {
public int f2 = -1;
}
- @Test void beanPropertyFieldNotInBeanProperties_usingBeanConfig() {
+ @Test void beanPropertyFieldNotInBeanConfig() {
var bc =
BeanContext.create().applyAnnotations(B2Config.class).build();
var bm = bc.newBeanMap(B2.class);
- assertTrue(bm.containsKey("f2"));
- assertEquals(-1, bm.get("f2"));
- bm.put("f2", -2);
+ assertFalse(bm.containsKey("f2")); // JUNEAU-248: Now
consistent with keySet()
+ assertEquals(-1, bm.get("f2")); // But get() still works
+ bm.put("f2", -2); // And put() still works
assertEquals(-2, bm.get("f2"));
assertFalse(bm.keySet().contains("f2"));
assertFalse(bm.entrySet().stream().map(Entry::getKey).toList().contains("f2"));