This is an automated email from the ASF dual-hosted git repository. ahuber pushed a commit to branch v4 in repository https://gitbox.apache.org/repos/asf/causeway.git
commit 674d68b7f871d2d9bcdb62ebbae1701e7991c70f Author: Andi Huber <[email protected]> AuthorDate: Mon Oct 6 17:17:17 2025 +0200 CAUSEWAY-2297: unmodifiable variants for List- and Set-Multimaps --- .../commons/internal/collections/_Multimaps.java | 154 +++++++++++---------- 1 file changed, 84 insertions(+), 70 deletions(-) diff --git a/commons/src/main/java/org/apache/causeway/commons/internal/collections/_Multimaps.java b/commons/src/main/java/org/apache/causeway/commons/internal/collections/_Multimaps.java index f6cfdee6be1..c195c98c9a0 100644 --- a/commons/src/main/java/org/apache/causeway/commons/internal/collections/_Multimaps.java +++ b/commons/src/main/java/org/apache/causeway/commons/internal/collections/_Multimaps.java @@ -43,7 +43,6 @@ import org.apache.causeway.commons.internal.base._Casts; import org.apache.causeway.commons.internal.exceptions._Exceptions; - import org.jspecify.annotations.NonNull; /** @@ -114,6 +113,48 @@ default NavigableMap<K, List<V>> asNavigableMapElseFail() { .unrecoverable("underlying map is not an instance of NavigableMap")); } + public ListMultimap<K, V> asUnmodifiable(); + + } + + private record ListMultimapWrapper<K, V>( + Map<K, List<V>> delegate, + Supplier<List<V>> elementCollectionFactory) implements ListMultimap<K, V> { + + @Override public int size() { return delegate.size(); } + @Override public boolean isEmpty() { return delegate.isEmpty(); } + @Override public boolean containsKey(final Object key) { return delegate.containsKey(key); } + @Override public boolean containsValue(final Object value) { return delegate.containsValue(value); } + @Override public List<V> get(final Object key) { return delegate.get(key); } + @Override public List<V> put(final K key, final List<V> value) { return delegate.put(key, value); } + @Override public List<V> remove(final Object key) { return delegate.remove(key); } + @Override public void putAll(final Map<? extends K, ? extends List<V>> m) { delegate.putAll(m); } + @Override public void clear() { delegate.clear(); } + @Override public Set<K> keySet() { return delegate.keySet(); } + @Override public Collection<List<V>> values() { return delegate.values(); } + @Override public Set<Entry<K, List<V>>> entrySet() { return delegate.entrySet(); } + + @Override + public void putElement(final K key, final V value) { + getOrElseNew(key).add(value); + } + + @Override + public List<V> getOrElseNew(final K key) { + var collection = delegate.computeIfAbsent(key, __->elementCollectionFactory.get()); + return collection; + } + + @Override + public Optional<NavigableMap<K, List<V>>> asNavigableMap() { + return delegate instanceof NavigableMap + ? Optional.of(_Casts.uncheckedCast(delegate)) + : Optional.empty(); + } + @Override + public ListMultimap<K, V> asUnmodifiable() { + return new ListMultimapWrapper<>(Collections.unmodifiableMap(delegate), elementCollectionFactory); + } } /** @@ -152,6 +193,42 @@ default public Stream<V> streamElements() { return values().stream() .flatMap(Collection::stream); } + + public SetMultimap<K, V> asUnmodifiable(); + } + + private record SetMultimapWrapper<K, V>( + Map<K, Set<V>> delegate, + Supplier<? extends Set<V>> elementCollectionFactory) implements SetMultimap<K, V> { + + @Override public int size() { return delegate.size(); } + @Override public boolean isEmpty() { return delegate.isEmpty(); } + @Override public boolean containsKey(final Object key) { return delegate.containsKey(key); } + @Override public boolean containsValue(final Object value) { return delegate.containsValue(value); } + @Override public Set<V> get(final Object key) { return delegate.get(key); } + @Override public Set<V> put(final K key, final Set<V> value) { return delegate.put(key, value); } + @Override public Set<V> remove(final Object key) { return delegate.remove(key); } + @Override public void putAll(final Map<? extends K, ? extends Set<V>> m) { delegate.putAll(m); } + @Override public void clear() { delegate.clear(); } + @Override public Set<K> keySet() { return delegate.keySet(); } + @Override public Collection<Set<V>> values() { return delegate.values(); } + @Override public Set<Entry<K, Set<V>>> entrySet() { return delegate.entrySet(); } + + @Override + public void putElement(final K key, final V value) { + getOrElseNew(key).add(value); + } + + @Override + public Set<V> getOrElseNew(final K key) { + var collection = delegate.computeIfAbsent(key, __->elementCollectionFactory.get()); + return collection; + } + + @Override + public SetMultimap<K, V> asUnmodifiable() { + return new SetMultimapWrapper<>(Collections.unmodifiableMap(delegate), elementCollectionFactory); + } } /** @@ -207,78 +284,15 @@ default public Stream<V> streamElements() { public static <K, V> ListMultimap<K, V> newListMultimap( final @NonNull Supplier<Map<K, List<V>>> mapFactory, final @NonNull Supplier<List<V>> elementCollectionFactory){ - - return new ListMultimap<K, V>() { - - final Map<K, List<V>> delegate = mapFactory.get(); - - @Override public int size() { return delegate.size(); } - @Override public boolean isEmpty() { return delegate.isEmpty(); } - @Override public boolean containsKey(final Object key) { return delegate.containsKey(key); } - @Override public boolean containsValue(final Object value) { return delegate.containsValue(value); } - @Override public List<V> get(final Object key) { return delegate.get(key); } - @Override public List<V> put(final K key, final List<V> value) { return delegate.put(key, value); } - @Override public List<V> remove(final Object key) { return delegate.remove(key); } - @Override public void putAll(final Map<? extends K, ? extends List<V>> m) { delegate.putAll(m); } - @Override public void clear() { delegate.clear(); } - @Override public Set<K> keySet() { return delegate.keySet(); } - @Override public Collection<List<V>> values() { return delegate.values(); } - @Override public Set<Entry<K, List<V>>> entrySet() { return delegate.entrySet(); } - - @Override - public void putElement(final K key, final V value) { - getOrElseNew(key).add(value); - } - - @Override - public List<V> getOrElseNew(final K key) { - var collection = delegate.computeIfAbsent(key, __->elementCollectionFactory.get()); - return collection; - } - - @Override - public Optional<NavigableMap<K, List<V>>> asNavigableMap() { - return delegate instanceof NavigableMap - ? Optional.of(_Casts.uncheckedCast(delegate)) - : Optional.empty(); - } - - }; + return new ListMultimapWrapper<>(mapFactory.get(), elementCollectionFactory); } - public static <K, V, S extends Set<V>> SetMultimap<K, V> newSetMultimap( - final @NonNull Supplier<? extends Map<K, S>> mapFactory, - final @NonNull Supplier<S> elementCollectionFactory){ - - return new SetMultimap<K, V>() { - final Map<K, Set<V>> delegate = _Casts.uncheckedCast(mapFactory.get()); - - @Override public int size() { return delegate.size(); } - @Override public boolean isEmpty() { return delegate.isEmpty(); } - @Override public boolean containsKey(final Object key) { return delegate.containsKey(key); } - @Override public boolean containsValue(final Object value) { return delegate.containsValue(value); } - @Override public Set<V> get(final Object key) { return delegate.get(key); } - @Override public Set<V> put(final K key, final Set<V> value) { return delegate.put(key, value); } - @Override public Set<V> remove(final Object key) { return delegate.remove(key); } - @Override public void putAll(final Map<? extends K, ? extends Set<V>> m) { delegate.putAll(m); } - @Override public void clear() { delegate.clear(); } - @Override public Set<K> keySet() { return delegate.keySet(); } - @Override public Collection<Set<V>> values() { return delegate.values(); } - @Override public Set<Entry<K, Set<V>>> entrySet() { return delegate.entrySet(); } - - @Override - public void putElement(final K key, final V value) { - getOrElseNew(key).add(value); - } - - @Override - public Set<V> getOrElseNew(final K key) { - var collection = delegate.computeIfAbsent(key, __->elementCollectionFactory.get()); - return collection; - } - - }; + public static <K, V, S extends Set<V>> SetMultimap<K, V> newSetMultimap( + final @NonNull Supplier<? extends Map<K, S>> mapFactory, + final @NonNull Supplier<S> elementCollectionFactory){ + final Map<K, Set<V>> delegate = _Casts.uncheckedCast(mapFactory.get()); + return new SetMultimapWrapper<K, V>(delegate, elementCollectionFactory); } public static <K1, K2, V> MapMultimap<K1, K2, V> newMapMultimap(
