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