{
+
+ V get(K key);
- Value get(Key key);
+ /**
+ * @since 7.1
+ */
+ default V computeIfAbsent(K key,
+ Function super K, ? extends V> mappingFunction) {
+ requireNonNull(mappingFunction);
+ if (get(key) == null) {
+ putIfAbsent(key, mappingFunction.apply(key));
+ }
+ return get(key);
+ }
- void put(Key key, Value value);
+ void put(K key, V value);
- void putIfAbsent(Key key, Value value);
+ void putIfAbsent(K key, V value);
int size();
diff --git a/core/src/main/java/org/apache/struts2/ognl/OgnlCaffeineCache.java b/core/src/main/java/org/apache/struts2/ognl/OgnlCaffeineCache.java
index 22ba4c62ec..b7f5b2750b 100644
--- a/core/src/main/java/org/apache/struts2/ognl/OgnlCaffeineCache.java
+++ b/core/src/main/java/org/apache/struts2/ognl/OgnlCaffeineCache.java
@@ -18,6 +18,8 @@
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
+import java.util.function.Function;
+
/**
* This OGNL Cache implementation is backed by {@link Caffeine} which uses the Window TinyLfu algorithm.
*
@@ -46,6 +48,11 @@ public V get(K key) {
return cache.getIfPresent(key);
}
+ @Override
+ public V computeIfAbsent(K key, Function super K, ? extends V> mappingFunction) {
+ return cache.asMap().computeIfAbsent(key, mappingFunction);
+ }
+
@Override
public void put(K key, V value) {
cache.put(key, value);
diff --git a/core/src/main/java/org/apache/struts2/ognl/OgnlDefaultCache.java b/core/src/main/java/org/apache/struts2/ognl/OgnlDefaultCache.java
index 727c2177d1..391944a10c 100644
--- a/core/src/main/java/org/apache/struts2/ognl/OgnlDefaultCache.java
+++ b/core/src/main/java/org/apache/struts2/ognl/OgnlDefaultCache.java
@@ -17,6 +17,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
/**
* Basic OGNL cache implementation.
@@ -45,16 +46,21 @@ public V get(K key) {
return ognlCache.get(key);
}
+ @Override
+ public V computeIfAbsent(K key, Function super K, ? extends V> mappingFunction) {
+ return ognlCache.computeIfAbsent(key, mappingFunction);
+ }
+
@Override
public void put(K key, V value) {
ognlCache.put(key, value);
- this.clearIfEvictionLimitExceeded();
+ clearIfEvictionLimitExceeded();
}
@Override
public void putIfAbsent(K key, V value) {
ognlCache.putIfAbsent(key, value);
- this.clearIfEvictionLimitExceeded();
+ clearIfEvictionLimitExceeded();
}
@Override
@@ -69,12 +75,12 @@ public void clear() {
@Override
public int getEvictionLimit() {
- return this.cacheEvictionLimit.get();
+ return cacheEvictionLimit.get();
}
@Override
- public void setEvictionLimit(int cacheEvictionLimit) {
- this.cacheEvictionLimit.set(cacheEvictionLimit);
+ public void setEvictionLimit(int newCacheEvictionLimit) {
+ cacheEvictionLimit.set(newCacheEvictionLimit);
}
/**
diff --git a/core/src/main/java/org/apache/struts2/ognl/OgnlLRUCache.java b/core/src/main/java/org/apache/struts2/ognl/OgnlLRUCache.java
index 6b43d71f23..fc995d438c 100644
--- a/core/src/main/java/org/apache/struts2/ognl/OgnlLRUCache.java
+++ b/core/src/main/java/org/apache/struts2/ognl/OgnlLRUCache.java
@@ -19,6 +19,7 @@
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
/**
* A basic OGNL LRU cache implementation.
@@ -54,6 +55,11 @@ public V get(K key) {
return ognlLRUCache.get(key);
}
+ @Override
+ public V computeIfAbsent(K key, Function super K, ? extends V> mappingFunction) {
+ return ognlLRUCache.computeIfAbsent(key, mappingFunction);
+ }
+
@Override
public void put(K key, V value) {
ognlLRUCache.put(key, value);
diff --git a/core/src/main/java/org/apache/struts2/ognl/OgnlUtil.java b/core/src/main/java/org/apache/struts2/ognl/OgnlUtil.java
index 95bee5f430..4d51ff2949 100644
--- a/core/src/main/java/org/apache/struts2/ognl/OgnlUtil.java
+++ b/core/src/main/java/org/apache/struts2/ognl/OgnlUtil.java
@@ -18,12 +18,6 @@
*/
package org.apache.struts2.ognl;
-import org.apache.struts2.conversion.impl.XWorkConverter;
-import org.apache.struts2.inject.Container;
-import org.apache.struts2.inject.Inject;
-import org.apache.struts2.ognl.accessor.RootAccessor;
-import org.apache.struts2.util.CompoundRoot;
-import org.apache.struts2.util.reflection.ReflectionException;
import ognl.ClassResolver;
import ognl.Ognl;
import ognl.OgnlContext;
@@ -35,7 +29,12 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsConstants;
-import org.apache.struts2.ognl.OgnlGuard;
+import org.apache.struts2.conversion.impl.XWorkConverter;
+import org.apache.struts2.inject.Container;
+import org.apache.struts2.inject.Inject;
+import org.apache.struts2.ognl.accessor.RootAccessor;
+import org.apache.struts2.util.CompoundRoot;
+import org.apache.struts2.util.reflection.ReflectionException;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
@@ -676,13 +675,19 @@ public BeanInfo getBeanInfo(Object from) throws IntrospectionException {
* @throws IntrospectionException is thrown if an exception occurs during introspection.
*/
public BeanInfo getBeanInfo(Class> clazz) throws IntrospectionException {
- synchronized (beanInfoCache) {
- BeanInfo beanInfo = beanInfoCache.get(clazz);
- if (beanInfo == null) {
- beanInfo = Introspector.getBeanInfo(clazz, Object.class);
- beanInfoCache.putIfAbsent(clazz, beanInfo);
+ try {
+ return beanInfoCache.computeIfAbsent(clazz, k -> {
+ try {
+ return Introspector.getBeanInfo(k, Object.class);
+ } catch (IntrospectionException e) {
+ throw new IllegalArgumentException(e);
+ }
+ });
+ } catch (IllegalArgumentException e) {
+ if (e.getCause() instanceof IntrospectionException innerEx) {
+ throw innerEx;
}
- return beanInfo;
+ throw e;
}
}
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 71823b47e5..a574af1c22 100644
--- a/core/src/main/java/org/apache/struts2/util/ProxyUtil.java
+++ b/core/src/main/java/org/apache/struts2/util/ProxyUtil.java
@@ -26,15 +26,19 @@
import org.apache.struts2.ognl.OgnlCacheFactory;
import org.hibernate.Hibernate;
import org.hibernate.proxy.HibernateProxy;
+import org.springframework.aop.SpringProxy;
+import org.springframework.aop.TargetClassAware;
+import org.springframework.aop.framework.Advised;
+import org.springframework.aop.framework.AopProxyUtils;
+import org.springframework.aop.support.AopUtils;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Proxy;
import static java.lang.reflect.Modifier.isPublic;
+import static java.lang.reflect.Modifier.isStatic;
/**
* ProxyUtil
@@ -44,17 +48,14 @@
*
*/
public class ProxyUtil {
- private static final String SPRING_ADVISED_CLASS_NAME = "org.springframework.aop.framework.Advised";
- private static final String SPRING_SPRINGPROXY_CLASS_NAME = "org.springframework.aop.SpringProxy";
- private static final String SPRING_SINGLETONTARGETSOURCE_CLASS_NAME = "org.springframework.aop.target.SingletonTargetSource";
- private static final String SPRING_TARGETCLASSAWARE_CLASS_NAME = "org.springframework.aop.TargetClassAware";
- private static final String HIBERNATE_HIBERNATEPROXY_CLASS_NAME = "org.hibernate.proxy.HibernateProxy";
private static final int CACHE_MAX_SIZE = 10000;
private static final int CACHE_INITIAL_CAPACITY = 256;
private static final OgnlCache, Boolean> isProxyCache = new DefaultOgnlCacheFactory, Boolean>(
CACHE_MAX_SIZE, OgnlCacheFactory.CacheType.WTLFU, CACHE_INITIAL_CAPACITY).buildOgnlCache();
private static final OgnlCache isProxyMemberCache = new DefaultOgnlCacheFactory(
CACHE_MAX_SIZE, OgnlCacheFactory.CacheType.WTLFU, CACHE_INITIAL_CAPACITY).buildOgnlCache();
+ private static final OgnlCache