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

lukaszlenart pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/struts.git


The following commit(s) were added to refs/heads/main by this push:
     new d276b2dde WW-5622 perf(core): optimize Hibernate proxy detection when 
Hibernate is absent (#1649)
d276b2dde is described below

commit d276b2dded8ec38ac6c4ea82a121e6774bd5fe7a
Author: Lukasz Lenart <[email protected]>
AuthorDate: Sun Apr 5 18:30:44 2026 +0200

    WW-5622 perf(core): optimize Hibernate proxy detection when Hibernate is 
absent (#1649)
    
    Detect Hibernate availability once at class-load time via Class.forName()
    and short-circuit all Hibernate-related methods immediately when absent.
    This eliminates repeated LinkageError/NoClassDefFoundError exceptions
    that cause significant performance degradation in applications without
    Hibernate on the classpath.
    
    Fixes https://issues.apache.org/jira/browse/WW-5622
    
    Co-authored-by: Claude Opus 4.6 <[email protected]>
---
 .../java/org/apache/struts2/util/ProxyUtil.java    | 16 +++++++++++++++-
 .../apache/struts2/util/StrutsProxyService.java    | 22 +++++++++++++++++++++-
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/core/src/main/java/org/apache/struts2/util/ProxyUtil.java 
b/core/src/main/java/org/apache/struts2/util/ProxyUtil.java
index 8117807d4..6ec3679ce 100644
--- a/core/src/main/java/org/apache/struts2/util/ProxyUtil.java
+++ b/core/src/main/java/org/apache/struts2/util/ProxyUtil.java
@@ -57,6 +57,17 @@ public class ProxyUtil {
     private static final OgnlCache<Member, Boolean> isProxyMemberCache = new 
DefaultOgnlCacheFactory<Member, Boolean>(
             CACHE_MAX_SIZE, OgnlCacheFactory.CacheType.BASIC, 
CACHE_INITIAL_CAPACITY).buildOgnlCache();
 
+    private static final boolean HIBERNATE_AVAILABLE = isHibernateAvailable();
+
+    private static boolean isHibernateAvailable() {
+        try {
+            Class.forName("org.hibernate.proxy.HibernateProxy");
+            return true;
+        } catch (ClassNotFoundException e) {
+            return false;
+        }
+    }
+
     /**
      * Determine the ultimate target class of the given instance, traversing
      * not only a top-level proxy but any number of nested proxies as well 
&mdash;
@@ -121,8 +132,9 @@ public class ProxyUtil {
      */
     @Deprecated(since = "7.2")
     public static boolean isHibernateProxy(Object object) {
+        if (!HIBERNATE_AVAILABLE || object == null) return false;
         try {
-            return object != null && 
HibernateProxy.class.isAssignableFrom(object.getClass());
+            return HibernateProxy.class.isAssignableFrom(object.getClass());
         } catch (LinkageError ignored) {
             return false;
         }
@@ -137,6 +149,7 @@ public class ProxyUtil {
      */
     @Deprecated(since = "7.2")
     public static boolean isHibernateProxyMember(Member member) {
+        if (!HIBERNATE_AVAILABLE) return false;
         try {
             return hasMember(HibernateProxy.class, member);
         } catch (LinkageError ignored) {
@@ -220,6 +233,7 @@ public class ProxyUtil {
      */
     @Deprecated(since = "7.2")
     public static Object getHibernateProxyTarget(Object object) {
+        if (!HIBERNATE_AVAILABLE) return object;
         try {
             return Hibernate.unproxy(object);
         } catch (LinkageError ignored) {
diff --git a/core/src/main/java/org/apache/struts2/util/StrutsProxyService.java 
b/core/src/main/java/org/apache/struts2/util/StrutsProxyService.java
index 76c06f469..ee2a3ca70 100644
--- a/core/src/main/java/org/apache/struts2/util/StrutsProxyService.java
+++ b/core/src/main/java/org/apache/struts2/util/StrutsProxyService.java
@@ -48,6 +48,17 @@ import static java.lang.reflect.Modifier.isStatic;
  */
 public class StrutsProxyService implements ProxyService {
 
+    private static final boolean HIBERNATE_AVAILABLE = isHibernateAvailable();
+
+    private static boolean isHibernateAvailable() {
+        try {
+            Class.forName("org.hibernate.proxy.HibernateProxy");
+            return true;
+        } catch (ClassNotFoundException e) {
+            return false;
+        }
+    }
+
     private final OgnlCache<Class<?>, Boolean> isProxyCache;
     private final OgnlCache<Member, Boolean> isProxyMemberCache;
 
@@ -90,8 +101,11 @@ public class StrutsProxyService implements ProxyService {
 
     @Override
     public boolean isHibernateProxy(Object object) {
+        if (!HIBERNATE_AVAILABLE || object == null) {
+            return false;
+        }
         try {
-            return object != null && 
HibernateProxy.class.isAssignableFrom(object.getClass());
+            return HibernateProxy.class.isAssignableFrom(object.getClass());
         } catch (LinkageError ignored) {
             return false;
         }
@@ -99,6 +113,9 @@ public class StrutsProxyService implements ProxyService {
 
     @Override
     public boolean isHibernateProxyMember(Member member) {
+        if (!HIBERNATE_AVAILABLE) {
+            return false;
+        }
         try {
             return hasMember(HibernateProxy.class, member);
         } catch (LinkageError ignored) {
@@ -108,6 +125,9 @@ public class StrutsProxyService implements ProxyService {
 
     @Override
     public Object getHibernateProxyTarget(Object object) {
+        if (!HIBERNATE_AVAILABLE) {
+            return object;
+        }
         try {
             return Hibernate.unproxy(object);
         } catch (LinkageError ignored) {

Reply via email to