1
1
/*
2
- * Copyright 2002-2018 the original author or authors.
2
+ * Copyright 2002-2020 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
63
63
* <p>Individual expressions can be compiled by calling {@code SpelCompiler.compile(expression)}.
64
64
*
65
65
* @author Andy Clement
66
+ * @author Juergen Hoeller
66
67
* @since 4.1
67
68
*/
68
69
public final class SpelCompiler implements Opcodes {
69
70
70
- private static final Log logger = LogFactory .getLog (SpelCompiler .class );
71
-
72
71
private static final int CLASSES_DEFINED_LIMIT = 100 ;
73
72
73
+ private static final Log logger = LogFactory .getLog (SpelCompiler .class );
74
+
74
75
// A compiler is created for each classloader, it manages a child class loader of that
75
76
// classloader and the child is used to load the compiled expressions.
76
77
private static final Map <ClassLoader , SpelCompiler > compilers = new ConcurrentReferenceHashMap <>();
77
78
79
+
78
80
// The child ClassLoader used to load the compiled expression classes
79
81
private ChildClassLoader ccl ;
80
82
@@ -90,7 +92,7 @@ private SpelCompiler(@Nullable ClassLoader classloader) {
90
92
/**
91
93
* Attempt compilation of the supplied expression. A check is made to see
92
94
* if it is compilable before compilation proceeds. The check involves
93
- * visiting all the nodes in the expression Ast and ensuring enough state
95
+ * visiting all the nodes in the expression AST and ensuring enough state
94
96
* is known about them that bytecode can be generated for them.
95
97
* @param expression the expression to compile
96
98
* @return an instance of the class implementing the compiled expression,
@@ -125,7 +127,7 @@ private int getNextSuffix() {
125
127
126
128
/**
127
129
* Generate the class that encapsulates the compiled expression and define it.
128
- * The generated class will be a subtype of CompiledExpression.
130
+ * The generated class will be a subtype of CompiledExpression.
129
131
* @param expressionToCompile the expression to be compiled
130
132
* @return the expression call, or {@code null} if the decision was to opt out of
131
133
* compilation during code generation
@@ -150,7 +152,7 @@ private Class<? extends CompiledExpression> createExpressionClass(SpelNodeImpl e
150
152
// Create getValue() method
151
153
mv = cw .visitMethod (ACC_PUBLIC , "getValue" ,
152
154
"(Ljava/lang/Object;Lorg/springframework/expression/EvaluationContext;)Ljava/lang/Object;" , null ,
153
- new String [ ] {"org/springframework/expression/EvaluationException" });
155
+ new String [] {"org/springframework/expression/EvaluationException" });
154
156
mv .visitCode ();
155
157
156
158
CodeFlow cf = new CodeFlow (className , cw );
@@ -187,7 +189,7 @@ private Class<? extends CompiledExpression> createExpressionClass(SpelNodeImpl e
187
189
188
190
/**
189
191
* Load a compiled expression class. Makes sure the classloaders aren't used too much
190
- * because they anchor compiled classes in memory and prevent GC. If you have expressions
192
+ * because they anchor compiled classes in memory and prevent GC. If you have expressions
191
193
* continually recompiling over time then by replacing the classloader periodically
192
194
* at least some of the older variants can be garbage collected.
193
195
* @param name the name of the class
@@ -202,6 +204,7 @@ private Class<? extends CompiledExpression> loadClass(String name, byte[] bytes)
202
204
return (Class <? extends CompiledExpression >) this .ccl .defineClass (name , bytes );
203
205
}
204
206
207
+
205
208
/**
206
209
* Factory method for compiler instances. The returned SpelCompiler will
207
210
* attach a class loader as the child of the given class loader and this
@@ -222,10 +225,12 @@ public static SpelCompiler getCompiler(@Nullable ClassLoader classLoader) {
222
225
}
223
226
224
227
/**
225
- * Request that an attempt is made to compile the specified expression. It may fail if
226
- * components of the expression are not suitable for compilation or the data types
227
- * involved are not suitable for compilation. Used for testing.
228
- * @return true if the expression was successfully compiled
228
+ * Request that an attempt is made to compile the specified expression.
229
+ * It may fail if components of the expression are not suitable for compilation
230
+ * or the data types involved are not suitable for compilation. Used for testing.
231
+ * @param expression the expression to compile
232
+ * @return {@code true} if the expression was successfully compiled,
233
+ * {@code false} otherwise
229
234
*/
230
235
public static boolean compile (Expression expression ) {
231
236
return (expression instanceof SpelExpression && ((SpelExpression ) expression ).compileExpression ());
@@ -256,18 +261,21 @@ public ChildClassLoader(@Nullable ClassLoader classLoader) {
256
261
super (NO_URLS , classLoader );
257
262
}
258
263
259
- int getClassesDefinedCount () {
260
- return this .classesDefinedCount ;
261
- }
262
-
263
264
public Class <?> defineClass (String name , byte [] bytes ) {
264
265
Class <?> clazz = super .defineClass (name , bytes , 0 , bytes .length );
265
266
this .classesDefinedCount ++;
266
267
return clazz ;
267
268
}
269
+
270
+ public int getClassesDefinedCount () {
271
+ return this .classesDefinedCount ;
272
+ }
268
273
}
269
274
270
275
276
+ /**
277
+ * An ASM ClassWriter extension bound to the SpelCompiler's ClassLoader.
278
+ */
271
279
private class ExpressionClassWriter extends ClassWriter {
272
280
273
281
public ExpressionClassWriter () {
0 commit comments