From 7cf3b95a9a0bd918219fc26a6f710e1e534ac815 Mon Sep 17 00:00:00 2001 From: rand0m86 Date: Mon, 21 Nov 2022 20:12:23 +0100 Subject: [PATCH] Override Java 1.8 default Map methods in ObservableMap This is to ensure that default map methods will be passed to the delegate, which is in this case an instance of ConcurrentHashMap. Without this change, an attempt to modify state variables via default methods will be delegated to default Map implementation, which is not thread safe. These methods are already overridden in ConcurrentHashMap. --- .../statemachine/support/ObservableMap.java | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/ObservableMap.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/ObservableMap.java index f2e4f90a6..4aa330ac8 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/ObservableMap.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/ObservableMap.java @@ -19,6 +19,9 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; import org.springframework.util.Assert; @@ -43,7 +46,7 @@ public class ObservableMap implements Map { public ObservableMap() { // default constructor needed for kryo, thus // we create delegate here, listener not needed. - delegate = new ConcurrentHashMap(); + delegate = new ConcurrentHashMap<>(); } /** @@ -132,6 +135,61 @@ public Set> entrySet() { return delegate.entrySet(); } + @Override + public V getOrDefault(Object key, V defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public void forEach(BiConsumer action) { + delegate.forEach(action); + } + + @Override + public void replaceAll(BiFunction function) { + delegate.replaceAll(function); + } + + @Override + public V putIfAbsent(K key, V value) { + return delegate.putIfAbsent(key, value); + } + + @Override + public boolean remove(Object key, Object value) { + return delegate.remove(key, value); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + return delegate.replace(key, oldValue, newValue); + } + + @Override + public V replace(K key, V value) { + return delegate.replace(key, value); + } + + @Override + public V computeIfAbsent(K key, Function mappingFunction) { + return delegate.computeIfAbsent(key, mappingFunction); + } + + @Override + public V computeIfPresent(K key, BiFunction remappingFunction) { + return delegate.computeIfPresent(key, remappingFunction); + } + + @Override + public V compute(K key, BiFunction remappingFunction) { + return delegate.compute(key, remappingFunction); + } + + @Override + public V merge(K key, V value, BiFunction remappingFunction) { + return delegate.merge(key, value, remappingFunction); + } + @Override public String toString() { return delegate.toString();