This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit f6f7af9c8759c66365c162560af1dff5c136e4ab Author: opencode <[email protected]> AuthorDate: Sun Oct 11 14:45:37 2026 +0200 Count entries with a null value in the size of a replicated map The size and the values collection only counted active entries that carried a non-null value, while the entry and key views included every active entry. A put of a null value is stored as an active local entry, because the replication gate does not accept a null value, so the size no longer matched the size of the entry set, which the map contract requires, and the empty check inherited the inconsistency. Both views now use the same filter as the entry and key views and count active entries with a null value, like the standard map implementations that permit null values do. --- .../tribes/tipis/AbstractReplicatedMap.java | 4 ++-- .../tribes/tipis/TestAbstractReplicatedMap.java | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java b/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java index e79ec1b6ab..3ef84d7777 100644 --- a/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java +++ b/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java @@ -1542,7 +1542,7 @@ public abstract class AbstractReplicatedMap<K, V> int counter = 0; for (Entry<K,MapEntry<K,V>> e : innerMap.entrySet()) { MapEntry<K,V> entry = e.getValue(); - if (entry != null && entry.isActive() && entry.getValue() != null) { + if (entry != null && entry.isActive()) { counter++; } } @@ -1569,7 +1569,7 @@ public abstract class AbstractReplicatedMap<K, V> List<V> values = new ArrayList<>(); for (Entry<K,MapEntry<K,V>> e : innerMap.entrySet()) { MapEntry<K,V> entry = e.getValue(); - if (entry != null && entry.isActive() && entry.getValue() != null) { + if (entry != null && entry.isActive()) { values.add(entry.getValue()); } } diff --git a/test/org/apache/catalina/tribes/tipis/TestAbstractReplicatedMap.java b/test/org/apache/catalina/tribes/tipis/TestAbstractReplicatedMap.java index e4da5f26fa..ae82476a55 100644 --- a/test/org/apache/catalina/tribes/tipis/TestAbstractReplicatedMap.java +++ b/test/org/apache/catalina/tribes/tipis/TestAbstractReplicatedMap.java @@ -244,4 +244,26 @@ public class TestAbstractReplicatedMap { Assert.assertNull(map.getInternal(key)); Assert.assertEquals(0, channel.sendCalls.get()); } + + /* + * A put stores an entry with a null value, so the size must count it like the entry and key + * views do. The size previously filtered such an entry out, breaking the map contract that the + * size equals the size of the entry set, and the isEmpty inherited the inconsistency. + */ + @Test + public void testSizeCountsActiveEntriesWithNullValue() throws Exception { + LazyReplicatedMap<String,String> map = new LazyReplicatedMap<String,String>( + (key, value) -> { + // Not made primary here + }, new TestChannel(), 1000, "TestAbstractReplicatedMap", null); + map.put("key", "value"); + map.put("other", null); + + Assert.assertEquals(2, map.size()); + Assert.assertEquals(2, map.entrySet().size()); + Assert.assertEquals(2, map.keySet().size()); + Assert.assertEquals(2, map.values().size()); + Assert.assertFalse(map.isEmpty()); + Assert.assertTrue(map.values().contains(null)); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
