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

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

commit 0ebb4a3a35284ed77874467e809c67ab227347ce
Author: Gary Gregory <[email protected]>
AuthorDate: Sun Nov 16 10:25:17 2025 -0500

    Refactor JXPathIntrospector internal static maps to use concurrent
    classes instead of synchronization
---
 src/changes/changes.xml                            |  1 +
 .../apache/commons/jxpath/JXPathIntrospector.java  | 40 ++++++++--------------
 2 files changed, 16 insertions(+), 25 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 80da5642..8d2fc7d0 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -51,6 +51,7 @@ The <action> type attribute can be add,update,fix,remove.
       <!-- FIX -->
       <action type="fix" dev="ggregory" due-to="Gary Gregory">POM 
assembly:single does not generate binary convenience files (tar/zip).</action>
       <action type="fix" dev="ggregory" due-to="Dima1224, Gary Gregory">Make 
dynamicPropertyHandlerMap in ValueUtils thread-safe #251.</action>
+      <action type="fix" dev="ggregory" due-to="Gary Gregory">Refactor 
JXPathIntrospector internal static maps to use concurrent classes instead of 
synchronization.</action>
       <!-- ADD -->
       <!-- UPDATE -->
       <action type="update" dev="ggregory" due-to="Gary Gregory, 
Dependabot">Bump org.apache.commons:commons-parent from 81 to 91 #239, #262, 
#265.</action>
diff --git a/src/main/java/org/apache/commons/jxpath/JXPathIntrospector.java 
b/src/main/java/org/apache/commons/jxpath/JXPathIntrospector.java
index b1ffac1e..c9a65683 100644
--- a/src/main/java/org/apache/commons/jxpath/JXPathIntrospector.java
+++ b/src/main/java/org/apache/commons/jxpath/JXPathIntrospector.java
@@ -17,10 +17,10 @@
 
 package org.apache.commons.jxpath;
 
-import java.util.Collections;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import org.apache.commons.jxpath.util.ClassLoaderUtil;
 
@@ -29,8 +29,8 @@ import org.apache.commons.jxpath.util.ClassLoaderUtil;
  */
 public class JXPathIntrospector {
 
-    private static Map<Class, JXPathBeanInfo> byClass = 
Collections.synchronizedMap(new HashMap<>());
-    private static Map<Class, JXPathBeanInfo> byInterface = 
Collections.synchronizedMap(new HashMap<>());
+    private static ConcurrentMap<Class, JXPathBeanInfo> byClass = new 
ConcurrentHashMap<>();
+    private static ConcurrentMap<Class, JXPathBeanInfo> byInterface = new 
ConcurrentHashMap<>();
     static {
         registerAtomicClass(Class.class);
         registerAtomicClass(Boolean.TYPE);
@@ -130,20 +130,16 @@ public class JXPathIntrospector {
      * @return JXPathBeanInfo
      */
     public static JXPathBeanInfo getBeanInfo(final Class beanClass) {
-        JXPathBeanInfo beanInfo = byClass.get(beanClass);
-        if (beanInfo == null) {
-            beanInfo = findDynamicBeanInfo(beanClass);
-            if (beanInfo == null) {
-                beanInfo = findInformant(beanClass);
-                if (beanInfo == null) {
-                    beanInfo = new JXPathBasicBeanInfo(beanClass);
+        return byClass.computeIfAbsent(beanClass, k -> {
+            JXPathBeanInfo value = findDynamicBeanInfo(beanClass);
+            if (value == null) {
+                value = findInformant(beanClass);
+                if (value == null) {
+                    value = new JXPathBasicBeanInfo(beanClass);
                 }
             }
-            synchronized (byClass) {
-                byClass.put(beanClass, beanInfo);
-            }
-        }
-        return beanInfo;
+            return value;
+        });
     }
 
     /**
@@ -175,9 +171,7 @@ public class JXPathIntrospector {
      * @param beanClass to register
      */
     public static void registerAtomicClass(final Class beanClass) {
-        synchronized (byClass) {
-            byClass.put(beanClass, new JXPathBasicBeanInfo(beanClass, true));
-        }
+        byClass.computeIfAbsent(beanClass, k -> new 
JXPathBasicBeanInfo(beanClass, true));
     }
 
     /**
@@ -190,13 +184,9 @@ public class JXPathIntrospector {
     public static void registerDynamicClass(final Class beanClass, final Class 
dynamicPropertyHandlerClass) {
         final JXPathBasicBeanInfo bi = new JXPathBasicBeanInfo(beanClass, 
dynamicPropertyHandlerClass);
         if (beanClass.isInterface()) {
-            synchronized (byInterface) {
-                byInterface.put(beanClass, bi);
-            }
+            byInterface.put(beanClass, bi);
         } else {
-            synchronized (byClass) {
-                byClass.put(beanClass, bi);
-            }
+            byClass.put(beanClass, bi);
         }
     }
 

Reply via email to