From 2ab632f15b72ebb50d7a88086378bc507adb8f52 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Tue, 7 Apr 2020 14:35:55 -0400 Subject: [PATCH] GH-3243: sync computeIfAbsent in StoredProcExec Fixes https://github.com/spring-projects/spring-integration/issues/3243 It turns out that `ConcurrentModificationException` is thrown from the `HashMap.computeIfAbsent(HashMap.java:1134)` since Java 9 when the map is modified concurrently independently from the key we try to modify * Check for the value presence before computing * `synchronized(this.jdbcCallOperationsMap)` around `computeIfAbsent()` when `get() == null` **Cherry-pick to 5.2.x** --- .../integration/jdbc/StoredProcExecutor.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcExecutor.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcExecutor.java index 7f0b0e918b5..f9556e1514c 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcExecutor.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcExecutor.java @@ -62,6 +62,8 @@ public class StoredProcExecutor implements BeanFactoryAware, InitializingBean { private final DataSource dataSource; + private final Object jdbcCallOperationsMapMonitor = new Object(); + private Map> returningResultSetRowMappers = new HashMap<>(0); private EvaluationContext evaluationContext; @@ -296,7 +298,14 @@ private Map executeStoredProcedureInternal(Object input, String } private SimpleJdbcCallOperations obtainSimpleJdbcCall(String storedProcedureName) { - return this.jdbcCallOperationsMap.computeIfAbsent(storedProcedureName, this::createSimpleJdbcCall); + SimpleJdbcCallOperations operations = this.jdbcCallOperationsMap.get(storedProcedureName); + if (operations == null) { + synchronized (this.jdbcCallOperationsMapMonitor) { + operations = + this.jdbcCallOperationsMap.computeIfAbsent(storedProcedureName, this::createSimpleJdbcCall); + } + } + return operations; } //~~~~~Setters for Properties~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~