Increase scope of regex pattern cache for the SpEL `matches` operator
Prior to this commit, the pattern cache for the SpEL `matches` operator
only applied to expressions such as the following where the same
`matches` operator is invoked multiple times with different input:
"map.keySet().?[#this matches '.+xyz']"
The pattern cache did not apply to expressions such as the following
where the same pattern ('.+xyz') is used in multiple `matches`
operations:
"foo matches '.+xyz' AND bar matches '.+xyz'"
This commit addresses this by moving the instance of the pattern cache
map from OperatorMatches to InternalSpelExpressionParser so that the
cache can be reused for all `matches` operations for the given parser.
Closes gh-30140
This commit is contained in:
parent
4a3518b4d6
commit
935c29e3dd
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -43,13 +43,28 @@ public class OperatorMatches extends Operator {
|
|||
|
||||
private static final int PATTERN_ACCESS_THRESHOLD = 1000000;
|
||||
|
||||
private final ConcurrentMap<String, Pattern> patternCache = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<String, Pattern> patternCache;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@link OperatorMatches} instance.
|
||||
* @deprecated as of Spring Framework 5.3.26 in favor of invoking
|
||||
* {@link #OperatorMatches(ConcurrentMap, int, int, SpelNodeImpl...)}
|
||||
* with a shared pattern cache instead
|
||||
*/
|
||||
@Deprecated(since = "5.3.26")
|
||||
public OperatorMatches(int startPos, int endPos, SpelNodeImpl... operands) {
|
||||
super("matches", startPos, endPos, operands);
|
||||
this(new ConcurrentHashMap<>(), startPos, endPos, operands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link OperatorMatches} instance with a shared pattern cache.
|
||||
* @since 5.3.26
|
||||
*/
|
||||
public OperatorMatches(ConcurrentMap<String, Pattern> patternCache, int startPos, int endPos, SpelNodeImpl... operands) {
|
||||
super("matches", startPos, endPos, operands);
|
||||
this.patternCache = patternCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the first operand matches the regex specified as the second operand.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -21,6 +21,8 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.expression.ParseException;
|
||||
|
|
@ -83,6 +85,7 @@ import org.springframework.util.StringUtils;
|
|||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
||||
|
|
@ -95,6 +98,9 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
// For rules that build nodes, they are stacked here for return
|
||||
private final Deque<SpelNodeImpl> constructedNodes = new ArrayDeque<>();
|
||||
|
||||
// Shared cache for compiled regex patterns
|
||||
private final ConcurrentMap<String, Pattern> patternCache = new ConcurrentHashMap<>();
|
||||
|
||||
// The expression being parsed
|
||||
private String expressionString = "";
|
||||
|
||||
|
|
@ -248,7 +254,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
}
|
||||
|
||||
if (tk == TokenKind.MATCHES) {
|
||||
return new OperatorMatches(t.startPos, t.endPos, expr, rhExpr);
|
||||
return new OperatorMatches(this.patternCache, t.startPos, t.endPos, expr, rhExpr);
|
||||
}
|
||||
|
||||
Assert.isTrue(tk == TokenKind.BETWEEN, "Between token expected");
|
||||
|
|
|
|||
Loading…
Reference in New Issue