Skip to content

Commit 611f251

Browse files
committed
Fix #34443: fix memory leak in SpecExpressionResolver
1 parent bc5a77b commit 611f251

1 file changed

Lines changed: 20 additions & 17 deletions

File tree

src/main/java/eu/openanalytics/containerproxy/spec/expression/SpecExpressionResolver.java

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222

2323
import com.fasterxml.jackson.databind.JsonNode;
2424
import com.fasterxml.jackson.databind.node.ArrayNode;
25-
import com.google.common.base.Throwables;
25+
import com.github.benmanes.caffeine.cache.Cache;
26+
import com.github.benmanes.caffeine.cache.Caffeine;
27+
import com.github.benmanes.caffeine.cache.Scheduler;
2628
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
2729
import org.springframework.context.ApplicationContext;
2830
import org.springframework.context.ConfigurableApplicationContext;
@@ -45,8 +47,7 @@
4547

4648
import java.util.ArrayList;
4749
import java.util.List;
48-
import java.util.Map;
49-
import java.util.concurrent.ConcurrentHashMap;
50+
import java.util.concurrent.TimeUnit;
5051
import java.util.stream.Stream;
5152
import java.util.stream.StreamSupport;
5253

@@ -58,7 +59,10 @@ public class SpecExpressionResolver {
5859

5960
private final ApplicationContext appContext;
6061
private final ExpressionParser expressionParser;
61-
private final Map<SpecExpressionContext, StandardEvaluationContext> evaluationCache = new ConcurrentHashMap<>(8);
62+
private final Cache<SpecExpressionContext, StandardEvaluationContext> evaluationCache = Caffeine.newBuilder()
63+
.scheduler(Scheduler.systemScheduler())
64+
.expireAfterAccess(1, TimeUnit.MINUTES)
65+
.build();
6266

6367
private final ParserContext beanExpressionParserContext = new ParserContext() {
6468
@Override
@@ -91,20 +95,19 @@ public <T> T evaluate(String expression, SpecExpressionContext context, Class<T>
9195

9296
ConfigurableBeanFactory beanFactory = ((ConfigurableApplicationContext) appContext).getBeanFactory();
9397

94-
StandardEvaluationContext sec = evaluationCache.get(context);
95-
if (sec == null) {
96-
sec = new StandardEvaluationContext();
97-
sec.setRootObject(context);
98-
sec.addPropertyAccessor(new BeanExpressionContextAccessor());
99-
sec.addPropertyAccessor(new BeanFactoryAccessor());
100-
sec.addPropertyAccessor(new MapAccessor());
101-
sec.addPropertyAccessor(new EnvironmentAccessor());
102-
sec.setBeanResolver(new BeanFactoryResolver(appContext));
103-
sec.setTypeLocator(new StandardTypeLocator(beanFactory.getBeanClassLoader()));
98+
StandardEvaluationContext sec = evaluationCache.get(context, k -> {
99+
StandardEvaluationContext result = new StandardEvaluationContext();
100+
result.setRootObject(context);
101+
result.addPropertyAccessor(new BeanExpressionContextAccessor());
102+
result.addPropertyAccessor(new BeanFactoryAccessor());
103+
result.addPropertyAccessor(new MapAccessor());
104+
result.addPropertyAccessor(new EnvironmentAccessor());
105+
result.setBeanResolver(new BeanFactoryResolver(appContext));
106+
result.setTypeLocator(new StandardTypeLocator(beanFactory.getBeanClassLoader()));
104107
ConversionService conversionService = beanFactory.getConversionService();
105-
if (conversionService != null) sec.setTypeConverter(new StandardTypeConverter(conversionService));
106-
evaluationCache.put(context, sec);
107-
}
108+
if (conversionService != null) result.setTypeConverter(new StandardTypeConverter(conversionService));
109+
return result;
110+
});
108111

109112
return expr.getValue(sec, resType);
110113
} catch (ExpressionException ex) {

0 commit comments

Comments
 (0)