This is an automated email from the ASF dual-hosted git repository.

garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-dbutils.git

commit 39d62c2e661ac753e09db90ff8707173f0dc79e1
Author: Gary Gregory <[email protected]>
AuthorDate: Sat Aug 22 08:58:51 2026 -0400

    Bump org.apache.commons:commons-parent from 103 to 104.
---
 pom.xml                                            |  2 +-
 src/changes/changes.xml                            |  3 ++-
 .../org/apache/commons/dbutils/QueryLoader.java    | 26 +++++++++++++++-------
 3 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/pom.xml b/pom.xml
index cee705f..c849a5a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,7 +19,7 @@
   <parent>
     <groupId>org.apache.commons</groupId>
     <artifactId>commons-parent</artifactId>
-    <version>103</version>
+    <version>104</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <groupId>commons-dbutils</groupId>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 105e34c..4ff9f7e 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -58,11 +58,12 @@ The <action> type attribute can be add,update,fix,remove.
       <action type="fix" dev="ggregory" due-to="Gary 
Gregory">ResultSetIterator.next() now throws IllegalStateException instead of 
RuntimeException to wrap cases of SQLException.</action>
       <action type="fix" dev="ggregory" due-to="Gary 
Gregory">ResultSetIterator.remove() now throws IllegalStateException instead of 
RuntimeException to wrap cases of SQLException.</action>
       <action type="fix" dev="ggregory" due-to="Gary Gregory, 
Matheus_Maas">org.apache.commons.dbutils.ResultSetIterator.next() now throws 
NoSuchElementException as defined in java.util.Iterator.next() #283.</action>
+      <action type="fix" dev="ggregory" due-to="Gary Gregory">Fix SpotBugs 
USO_UNSAFE_METHOD_SYNCHRONIZATION in QueryLoader.</action>
       <!-- ADD -->
       <action type="add" dev="ggregory" due-to="strangelookingnerd, Gary 
Gregory">BaseResultSetHandler implements ResultSet.</action>
       <!-- UPDATE -->
       <action dev="ggregory" type="update" due-to="Gary Gregory">Bump Java 
from 8 to 11.</action>
-      <action dev="ggregory" type="update" due-to="Gary Gregory">Bump 
commons-parent from 62 to 102 #256, #277, #295, #301, #305, #308, #314, #387, 
#403, #406.</action>
+      <action dev="ggregory" type="update" due-to="Gary Gregory">Bump 
commons-parent from 62 to 104 #256, #277, #295, #301, #305, #308, #314, #387, 
#403, #406.</action>
       <action dev="ggregory" type="update" due-to="Dependabot, Gary 
Gregory">Bump org.mockito:mockito-junit-jupiter from 5.14.2 to 5.23.0 #336, 
#359, #366, #389, #408.</action>
       <action dev="ggregory" type="update" due-to="Dependabot, Gary 
Gregory">Bump commons-jxpath:commons-jxpath from 1.3 to 1.4.0 #360.</action>
       <action dev="ggregory" type="update" due-to="Dependabot, Gary 
Gregory">Bump org.apache.commons:commons-lang3 from 3.17.0 to 3.20.0 
#372.</action>
diff --git a/src/main/java/org/apache/commons/dbutils/QueryLoader.java 
b/src/main/java/org/apache/commons/dbutils/QueryLoader.java
index 023f973..ef7ea0f 100644
--- a/src/main/java/org/apache/commons/dbutils/QueryLoader.java
+++ b/src/main/java/org/apache/commons/dbutils/QueryLoader.java
@@ -22,6 +22,9 @@ import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.regex.Pattern;
 
 /**
@@ -52,7 +55,7 @@ public class QueryLoader {
     /**
      * Maps query set names to Maps of their queries.
      */
-    private final Map<String, Map<String, String>> queries = new HashMap<>();
+    private final ConcurrentMap<String, Map<String, String>> queries = new 
ConcurrentHashMap<>();
 
     /**
      * QueryLoader constructor.
@@ -72,11 +75,18 @@ public class QueryLoader {
      * @return Map of query names to SQL values
      * @see java.util.Properties
      */
-    public synchronized Map<String, String> load(final String path) throws 
IOException {
-        Map<String, String> queryMap = this.queries.get(path);
-        if (queryMap == null) {
-            queryMap = loadQueries(path);
-            this.queries.put(path, queryMap);
+    public Map<String, String> load(final String path) throws IOException {
+        final AtomicReference<IOException> ioe = new AtomicReference<>();
+        final Map<String, String> queryMap = queries.computeIfAbsent(path, p 
-> {
+            try {
+                return loadQueries(p);
+            } catch (final IOException e) {
+                ioe.set(e);
+                return null;
+            }
+        });
+        if (ioe.get() != null) {
+            throw ioe.get();
         }
         return queryMap;
     }
@@ -118,7 +128,7 @@ public class QueryLoader {
      *
      * @param path The path that the queries were loaded from.
      */
-    public synchronized void unload(final String path) {
-        this.queries.remove(path);
+    public void unload(final String path) {
+        queries.remove(path);
     }
 }

Reply via email to