2020
2121import org .springframework .core .SpringProperties ;
2222import org .springframework .lang .Nullable ;
23+ import org .springframework .util .Assert ;
24+ import org .springframework .util .StringUtils ;
2325
2426/**
2527 * Configuration object for the SpEL expression parser.
@@ -39,9 +41,38 @@ public class SpelParserConfiguration {
3941 */
4042 public static final int DEFAULT_MAX_EXPRESSION_LENGTH = 10_000 ;
4143
42- /** System property to configure the default compiler mode for SpEL expression parsers: {@value}. */
44+ /**
45+ * Default maximum number of operations permitted during SpEL expression evaluation: {@value}.
46+ * @since 6.2.19
47+ * @see #SPRING_EXPRESSION_MAX_OPERATIONS_PROPERTY_NAME
48+ */
49+ public static final int DEFAULT_MAX_OPERATIONS = 10_000 ;
50+
51+ /**
52+ * System property to configure the default compiler mode for SpEL expression parsers: {@value}.
53+ * <p><strong>NOTE</strong>: Instead of relying on a global default, applications
54+ * and frameworks should ideally set an explicit custom value via the
55+ * {@link #SpelParserConfiguration(SpelCompilerMode, ClassLoader, boolean, boolean, int, int, int)}
56+ * constructor which provides complete configuration control and the ability
57+ * to override global defaults per use case.
58+ * <p>Can also be configured via the {@link SpringProperties} mechanism.
59+ */
4360 public static final String SPRING_EXPRESSION_COMPILER_MODE_PROPERTY_NAME = "spring.expression.compiler.mode" ;
4461
62+ /**
63+ * System property to configure the default maximum number of operations permitted
64+ * during SpEL expression evaluation: {@value}.
65+ * <p><strong>NOTE</strong>: Instead of relying on a global default, applications
66+ * and frameworks should ideally set an explicit custom value via the
67+ * {@link #SpelParserConfiguration(SpelCompilerMode, ClassLoader, boolean, boolean, int, int, int)}
68+ * constructor which provides complete configuration control and the ability
69+ * to override global defaults per use case.
70+ * <p>Can also be configured via the {@link SpringProperties} mechanism.
71+ * @since 6.2.19
72+ * @see #DEFAULT_MAX_OPERATIONS
73+ */
74+ public static final String SPRING_EXPRESSION_MAX_OPERATIONS_PROPERTY_NAME = "spring.expression.maxOperations" ;
75+
4576
4677 private static final SpelCompilerMode defaultCompilerMode ;
4778
@@ -65,50 +96,85 @@ public class SpelParserConfiguration {
6596
6697 private final int maximumExpressionLength ;
6798
99+ private final int maximumOperations ;
100+
68101
69102 /**
70103 * Create a new {@code SpelParserConfiguration} instance with default settings.
104+ * <p><strong>NOTE</strong>: Favor the
105+ * {@link #SpelParserConfiguration(SpelCompilerMode, ClassLoader, boolean, boolean, int, int, int)}
106+ * constructor for complete configuration control and the ability to override
107+ * global defaults per use case.
108+ * @see #SPRING_EXPRESSION_COMPILER_MODE_PROPERTY_NAME
109+ * @see #SPRING_EXPRESSION_MAX_OPERATIONS_PROPERTY_NAME
71110 */
72111 public SpelParserConfiguration () {
73112 this (null , null , false , false , Integer .MAX_VALUE );
74113 }
75114
76115 /**
77116 * Create a new {@code SpelParserConfiguration} instance.
78- * @param compilerMode the compiler mode for the parser
79- * @param compilerClassLoader the ClassLoader to use as the basis for expression compilation
117+ * <p><strong>NOTE</strong>: Favor the
118+ * {@link #SpelParserConfiguration(SpelCompilerMode, ClassLoader, boolean, boolean, int, int, int)}
119+ * constructor for complete configuration control and the ability to override
120+ * global defaults per use case.
121+ * @param compilerMode the compiler mode that parsers using this configuration
122+ * should use; or {@code null} to use the default mode
123+ * @param compilerClassLoader the {@code ClassLoader} to use as the basis for
124+ * expression compilation; or {@code null} to use the default {@code ClassLoader}
125+ * @see #SPRING_EXPRESSION_COMPILER_MODE_PROPERTY_NAME
126+ * @see #SPRING_EXPRESSION_MAX_OPERATIONS_PROPERTY_NAME
80127 */
81128 public SpelParserConfiguration (@ Nullable SpelCompilerMode compilerMode , @ Nullable ClassLoader compilerClassLoader ) {
82129 this (compilerMode , compilerClassLoader , false , false , Integer .MAX_VALUE );
83130 }
84131
85132 /**
86133 * Create a new {@code SpelParserConfiguration} instance.
134+ * <p><strong>NOTE</strong>: Favor the
135+ * {@link #SpelParserConfiguration(SpelCompilerMode, ClassLoader, boolean, boolean, int, int, int)}
136+ * constructor for complete configuration control and the ability to override
137+ * global defaults per use case.
87138 * @param autoGrowNullReferences if null references should automatically grow
88139 * @param autoGrowCollections if collections should automatically grow
89- * @see #SpelParserConfiguration(boolean, boolean, int)
140+ * @see #SPRING_EXPRESSION_COMPILER_MODE_PROPERTY_NAME
141+ * @see #SPRING_EXPRESSION_MAX_OPERATIONS_PROPERTY_NAME
90142 */
91143 public SpelParserConfiguration (boolean autoGrowNullReferences , boolean autoGrowCollections ) {
92144 this (null , null , autoGrowNullReferences , autoGrowCollections , Integer .MAX_VALUE );
93145 }
94146
95147 /**
96148 * Create a new {@code SpelParserConfiguration} instance.
149+ * <p><strong>NOTE</strong>: Favor the
150+ * {@link #SpelParserConfiguration(SpelCompilerMode, ClassLoader, boolean, boolean, int, int, int)}
151+ * constructor for complete configuration control and the ability to override
152+ * global defaults per use case.
97153 * @param autoGrowNullReferences if null references should automatically grow
98154 * @param autoGrowCollections if collections should automatically grow
99- * @param maximumAutoGrowSize the maximum size that the collection can auto grow
155+ * @param maximumAutoGrowSize the maximum size to which a collection can auto grow
156+ * @see #SPRING_EXPRESSION_COMPILER_MODE_PROPERTY_NAME
157+ * @see #SPRING_EXPRESSION_MAX_OPERATIONS_PROPERTY_NAME
100158 */
101159 public SpelParserConfiguration (boolean autoGrowNullReferences , boolean autoGrowCollections , int maximumAutoGrowSize ) {
102160 this (null , null , autoGrowNullReferences , autoGrowCollections , maximumAutoGrowSize );
103161 }
104162
105163 /**
106164 * Create a new {@code SpelParserConfiguration} instance.
107- * @param compilerMode the compiler mode that parsers using this configuration object should use
108- * @param compilerClassLoader the ClassLoader to use as the basis for expression compilation
165+ * <p><strong>NOTE</strong>: Favor the
166+ * {@link #SpelParserConfiguration(SpelCompilerMode, ClassLoader, boolean, boolean, int, int, int)}
167+ * constructor for complete configuration control and the ability to override
168+ * global defaults per use case.
169+ * @param compilerMode the compiler mode that parsers using this configuration
170+ * should use; or {@code null} to use the default mode
171+ * @param compilerClassLoader the {@code ClassLoader} to use as the basis for
172+ * expression compilation; or {@code null} to use the default {@code ClassLoader}
109173 * @param autoGrowNullReferences if null references should automatically grow
110174 * @param autoGrowCollections if collections should automatically grow
111- * @param maximumAutoGrowSize the maximum size that the collection can auto grow
175+ * @param maximumAutoGrowSize the maximum size to which a collection can auto grow
176+ * @see #SPRING_EXPRESSION_COMPILER_MODE_PROPERTY_NAME
177+ * @see #SPRING_EXPRESSION_MAX_OPERATIONS_PROPERTY_NAME
112178 */
113179 public SpelParserConfiguration (@ Nullable SpelCompilerMode compilerMode , @ Nullable ClassLoader compilerClassLoader ,
114180 boolean autoGrowNullReferences , boolean autoGrowCollections , int maximumAutoGrowSize ) {
@@ -119,24 +185,60 @@ public SpelParserConfiguration(@Nullable SpelCompilerMode compilerMode, @Nullabl
119185
120186 /**
121187 * Create a new {@code SpelParserConfiguration} instance.
122- * @param compilerMode the compiler mode that parsers using this configuration object should use
123- * @param compilerClassLoader the ClassLoader to use as the basis for expression compilation
188+ * <p><strong>NOTE</strong>: Favor the
189+ * {@link #SpelParserConfiguration(SpelCompilerMode, ClassLoader, boolean, boolean, int, int, int)}
190+ * constructor for complete configuration control and the ability to override
191+ * global defaults per use case.
192+ * @param compilerMode the compiler mode that parsers using this configuration
193+ * should use; or {@code null} to use the default mode
194+ * @param compilerClassLoader the {@code ClassLoader} to use as the basis for
195+ * expression compilation; or {@code null} to use the default {@code ClassLoader}
124196 * @param autoGrowNullReferences if null references should automatically grow
125197 * @param autoGrowCollections if collections should automatically grow
126- * @param maximumAutoGrowSize the maximum size that a collection can auto grow
198+ * @param maximumAutoGrowSize the maximum size to which a collection can auto grow
127199 * @param maximumExpressionLength the maximum length of a SpEL expression;
128200 * must be a positive number
129201 * @since 5.2.25
202+ * @see #SPRING_EXPRESSION_COMPILER_MODE_PROPERTY_NAME
203+ * @see #SPRING_EXPRESSION_MAX_OPERATIONS_PROPERTY_NAME
130204 */
131205 public SpelParserConfiguration (@ Nullable SpelCompilerMode compilerMode , @ Nullable ClassLoader compilerClassLoader ,
132206 boolean autoGrowNullReferences , boolean autoGrowCollections , int maximumAutoGrowSize , int maximumExpressionLength ) {
133207
134- this .compilerMode = (compilerMode != null ? compilerMode : defaultCompilerMode );
208+ this ((compilerMode != null ? compilerMode : defaultCompilerMode ), compilerClassLoader , autoGrowNullReferences ,
209+ autoGrowCollections , maximumAutoGrowSize , maximumExpressionLength , retrieveMaxOperations ());
210+ }
211+
212+ /**
213+ * Create a new {@code SpelParserConfiguration} instance.
214+ * @param compilerMode the compiler mode that parsers using this configuration
215+ * should use; must not be {@code null}
216+ * @param compilerClassLoader the {@code ClassLoader} to use as the basis for
217+ * expression compilation; or {@code null} to use the default {@code ClassLoader}
218+ * @param autoGrowNullReferences if null references should automatically grow
219+ * @param autoGrowCollections if collections should automatically grow
220+ * @param maximumAutoGrowSize the maximum size to which a collection can auto grow
221+ * @param maximumExpressionLength the maximum length of a SpEL expression;
222+ * must be a positive number
223+ * @param maximumOperations the maximum number of operations permitted during
224+ * SpEL expression evaluation; must be a positive number
225+ * @since 6.2.19
226+ */
227+ public SpelParserConfiguration (SpelCompilerMode compilerMode , @ Nullable ClassLoader compilerClassLoader ,
228+ boolean autoGrowNullReferences , boolean autoGrowCollections , int maximumAutoGrowSize , int maximumExpressionLength ,
229+ int maximumOperations ) {
230+
231+ Assert .notNull (compilerMode , "'compilerMode' must not be null" );
232+ Assert .isTrue (maximumExpressionLength > 0 , "'maximumExpressionLength' must be a positive number" );
233+ Assert .isTrue (maximumOperations > 0 , "'maximumOperations' must be a positive number" );
234+
235+ this .compilerMode = compilerMode ;
135236 this .compilerClassLoader = compilerClassLoader ;
136237 this .autoGrowNullReferences = autoGrowNullReferences ;
137238 this .autoGrowCollections = autoGrowCollections ;
138239 this .maximumAutoGrowSize = maximumAutoGrowSize ;
139240 this .maximumExpressionLength = maximumExpressionLength ;
241+ this .maximumOperations = maximumOperations ;
140242 }
141243
142244
@@ -148,7 +250,7 @@ public SpelCompilerMode getCompilerMode() {
148250 }
149251
150252 /**
151- * Return the ClassLoader to use as the basis for expression compilation.
253+ * Return the {@code ClassLoader} to use as the basis for expression compilation.
152254 */
153255 @ Nullable
154256 public ClassLoader getCompilerClassLoader () {
@@ -170,7 +272,7 @@ public boolean isAutoGrowCollections() {
170272 }
171273
172274 /**
173- * Return the maximum size that a collection can auto grow.
275+ * Return the maximum size to which a collection can auto grow.
174276 */
175277 public int getMaximumAutoGrowSize () {
176278 return this .maximumAutoGrowSize ;
@@ -184,4 +286,32 @@ public int getMaximumExpressionLength() {
184286 return this .maximumExpressionLength ;
185287 }
186288
289+ /**
290+ * Return the maximum number of operations permitted during SpEL expression
291+ * evaluation.
292+ * @since 6.2.19
293+ */
294+ public int getMaximumOperations () {
295+ return this .maximumOperations ;
296+ }
297+
298+
299+ private static int retrieveMaxOperations () {
300+ String value = SpringProperties .getProperty (SPRING_EXPRESSION_MAX_OPERATIONS_PROPERTY_NAME );
301+ if (!StringUtils .hasText (value )) {
302+ return DEFAULT_MAX_OPERATIONS ;
303+ }
304+
305+ try {
306+ int maxOperations = Integer .parseInt (value .trim ());
307+ Assert .isTrue (maxOperations > 0 , () -> "Value [" + maxOperations + "] for system property [" +
308+ SPRING_EXPRESSION_MAX_OPERATIONS_PROPERTY_NAME + "] must be positive" );
309+ return maxOperations ;
310+ }
311+ catch (NumberFormatException ex ) {
312+ throw new IllegalArgumentException ("Failed to parse value for system property [" +
313+ SPRING_EXPRESSION_MAX_OPERATIONS_PROPERTY_NAME + "]: " + ex .getMessage (), ex );
314+ }
315+ }
316+
187317}
0 commit comments