This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 0cfd2c50bea5de632f2ddf80faaecae1519179fc 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 ead1263dd8..ac43555133 100644 --- a/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java +++ b/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java @@ -1537,7 +1537,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++; } } @@ -1564,7 +1564,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]
