This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch fix/WW-5622-hibernate-proxy-detection in repository https://gitbox.apache.org/repos/asf/struts.git
commit 496ad4eeb86149ab5695601a3439022cf0e10055 Author: Lukasz Lenart <[email protected]> AuthorDate: Sat Apr 4 11:47:41 2026 +0200 WW-5622 perf(core): optimize Hibernate proxy detection when Hibernate is absent 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 — @@ -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) {
