@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 2002 - 2018 the original author or authors .
* Copyright 2002 - 2020 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 .
@ -63,18 +63,20 @@ import org.springframework.util.StringUtils;
@@ -63,18 +63,20 @@ import org.springframework.util.StringUtils;
* < p > Individual expressions can be compiled by calling { @code SpelCompiler . compile ( expression ) } .
*
* @author Andy Clement
* @author Juergen Hoeller
* @since 4 . 1
* /
public final class SpelCompiler implements Opcodes {
private static final Log logger = LogFactory . getLog ( SpelCompiler . class ) ;
private static final int CLASSES_DEFINED_LIMIT = 100 ;
private static final Log logger = LogFactory . getLog ( SpelCompiler . class ) ;
// A compiler is created for each classloader, it manages a child class loader of that
// classloader and the child is used to load the compiled expressions.
private static final Map < ClassLoader , SpelCompiler > compilers = new ConcurrentReferenceHashMap < > ( ) ;
// The child ClassLoader used to load the compiled expression classes
private ChildClassLoader ccl ;
@ -90,7 +92,7 @@ public final class SpelCompiler implements Opcodes {
@@ -90,7 +92,7 @@ public final class SpelCompiler implements Opcodes {
/ * *
* Attempt compilation of the supplied expression . A check is made to see
* if it is compilable before compilation proceeds . The check involves
* visiting all the nodes in the expression Ast and ensuring enough state
* visiting all the nodes in the expression AST and ensuring enough state
* is known about them that bytecode can be generated for them .
* @param expression the expression to compile
* @return an instance of the class implementing the compiled expression ,
@ -125,7 +127,7 @@ public final class SpelCompiler implements Opcodes {
@@ -125,7 +127,7 @@ public final class SpelCompiler implements Opcodes {
/ * *
* Generate the class that encapsulates the compiled expression and define it .
* The generated class will be a subtype of CompiledExpression .
* The generated class will be a subtype of CompiledExpression .
* @param expressionToCompile the expression to be compiled
* @return the expression call , or { @code null } if the decision was to opt out of
* compilation during code generation
@ -150,7 +152,7 @@ public final class SpelCompiler implements Opcodes {
@@ -150,7 +152,7 @@ public final class SpelCompiler implements Opcodes {
// Create getValue() method
mv = cw . visitMethod ( ACC_PUBLIC , "getValue" ,
"(Ljava/lang/Object;Lorg/springframework/expression/EvaluationContext;)Ljava/lang/Object;" , null ,
new String [ ] { "org/springframework/expression/EvaluationException" } ) ;
new String [ ] { "org/springframework/expression/EvaluationException" } ) ;
mv . visitCode ( ) ;
CodeFlow cf = new CodeFlow ( className , cw ) ;
@ -187,11 +189,11 @@ public final class SpelCompiler implements Opcodes {
@@ -187,11 +189,11 @@ public final class SpelCompiler implements Opcodes {
/ * *
* Load a compiled expression class . Makes sure the classloaders aren ' t used too much
* because they anchor compiled classes in memory and prevent GC . If you have expressions
* because they anchor compiled classes in memory and prevent GC . If you have expressions
* continually recompiling over time then by replacing the classloader periodically
* at least some of the older variants can be garbage collected .
* @param name name of the class
* @param bytes bytecode for the class
* @param name the name of the class
* @param bytes the bytecode for the class
* @return the Class object for the compiled expression
* /
@SuppressWarnings ( "unchecked" )
@ -202,6 +204,7 @@ public final class SpelCompiler implements Opcodes {
@@ -202,6 +204,7 @@ public final class SpelCompiler implements Opcodes {
return ( Class < ? extends CompiledExpression > ) this . ccl . defineClass ( name , bytes ) ;
}
/ * *
* Factory method for compiler instances . The returned SpelCompiler will
* attach a class loader as the child of the given class loader and this
@ -222,10 +225,12 @@ public final class SpelCompiler implements Opcodes {
@@ -222,10 +225,12 @@ public final class SpelCompiler implements Opcodes {
}
/ * *
* Request that an attempt is made to compile the specified expression . It may fail if
* components of the expression are not suitable for compilation or the data types
* involved are not suitable for compilation . Used for testing .
* @return true if the expression was successfully compiled
* Request that an attempt is made to compile the specified expression .
* It may fail if components of the expression are not suitable for compilation
* or the data types involved are not suitable for compilation . Used for testing .
* @param expression the expression to compile
* @return { @code true } if the expression was successfully compiled ,
* { @code false } otherwise
* /
public static boolean compile ( Expression expression ) {
return ( expression instanceof SpelExpression & & ( ( SpelExpression ) expression ) . compileExpression ( ) ) ;
@ -256,18 +261,21 @@ public final class SpelCompiler implements Opcodes {
@@ -256,18 +261,21 @@ public final class SpelCompiler implements Opcodes {
super ( NO_URLS , classLoader ) ;
}
int getClassesDefinedCount ( ) {
return this . classesDefinedCount ;
}
public Class < ? > defineClass ( String name , byte [ ] bytes ) {
Class < ? > clazz = super . defineClass ( name , bytes , 0 , bytes . length ) ;
this . classesDefinedCount + + ;
return clazz ;
}
public int getClassesDefinedCount ( ) {
return this . classesDefinedCount ;
}
}
/ * *
* An ASM ClassWriter extension bound to the SpelCompiler ' s ClassLoader .
* /
private class ExpressionClassWriter extends ClassWriter {
public ExpressionClassWriter ( ) {