diff --git a/spring-context/src/main/java/org/springframework/context/expression/StandardBeanExpressionResolver.java b/spring-context/src/main/java/org/springframework/context/expression/StandardBeanExpressionResolver.java index b2cecd883e2..29ff4fcacfc 100644 --- a/spring-context/src/main/java/org/springframework/context/expression/StandardBeanExpressionResolver.java +++ b/spring-context/src/main/java/org/springframework/context/expression/StandardBeanExpressionResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -27,6 +27,7 @@ import org.springframework.core.convert.ConversionService; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.ParserContext; +import org.springframework.expression.spel.SpelParserConfiguration; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardTypeConverter; @@ -58,7 +59,7 @@ public class StandardBeanExpressionResolver implements BeanExpressionResolver { private String expressionSuffix = DEFAULT_EXPRESSION_SUFFIX; - private ExpressionParser expressionParser = new SpelExpressionParser(); + private ExpressionParser expressionParser; private final Map expressionCache = new ConcurrentHashMap(256); @@ -81,6 +82,23 @@ public class StandardBeanExpressionResolver implements BeanExpressionResolver { }; + /** + * Create a new {@code StandardBeanExpressionResolver} with default settings. + */ + public StandardBeanExpressionResolver() { + this.expressionParser = new SpelExpressionParser(); + } + + /** + * Create a new {@code StandardBeanExpressionResolver} with the given bean class loader, + * using it as the basis for expression compilation. + * @param beanClassLoader the factory's bean class loader + */ + public StandardBeanExpressionResolver(ClassLoader beanClassLoader) { + this.expressionParser = new SpelExpressionParser(new SpelParserConfiguration(null, beanClassLoader)); + } + + /** * Set the prefix that an expression string starts with. * The default is "#{". diff --git a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java index 24bd0340f3a..96c65bac8b2 100644 --- a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java @@ -548,7 +548,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. beanFactory.setBeanClassLoader(getClassLoader()); - beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver()); + beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks. diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/CodeFlow.java b/spring-expression/src/main/java/org/springframework/expression/spel/CodeFlow.java similarity index 85% rename from spring-expression/src/main/java/org/springframework/expression/spel/standard/CodeFlow.java rename to spring-expression/src/main/java/org/springframework/expression/spel/CodeFlow.java index 4cc1f1ad407..b77920bd51c 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/CodeFlow.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/CodeFlow.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2002-2014 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. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.expression.spel.standard; +package org.springframework.expression.spel; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -40,13 +40,15 @@ public class CodeFlow implements Opcodes { * sub-expressions like the expressions for the argument values in a method invocation * expression. */ - private Stack> compilationScopes; + private final Stack> compilationScopes; + public CodeFlow() { - compilationScopes = new Stack>(); - compilationScopes.add(new ArrayList()); + this.compilationScopes = new Stack>(); + this.compilationScopes.add(new ArrayList()); } + /** * Push the byte code to load the target (i.e. what was passed as the first argument * to CompiledExpression.getValue(target, context)) @@ -62,7 +64,7 @@ public class CodeFlow implements Opcodes { */ public void pushDescriptor(String descriptor) { Assert.notNull(descriptor); - compilationScopes.peek().add(descriptor); + this.compilationScopes.peek().add(descriptor); } /** @@ -71,7 +73,7 @@ public class CodeFlow implements Opcodes { * each argument will be evaluated in a new scope. */ public void enterCompilationScope() { - compilationScopes.push(new ArrayList()); + this.compilationScopes.push(new ArrayList()); } /** @@ -80,18 +82,17 @@ public class CodeFlow implements Opcodes { * returns us to the previous (outer) scope. */ public void exitCompilationScope() { - compilationScopes.pop(); + this.compilationScopes.pop(); } /** - * @return the descriptor for the item currently on top of the stack (in the current - * scope) + * @return the descriptor for the item currently on top of the stack (in the current scope) */ public String lastDescriptor() { - if (compilationScopes.peek().size()==0) { + if (this.compilationScopes.peek().size() == 0) { return null; } - return compilationScopes.peek().get(compilationScopes.peek().size()-1); + return this.compilationScopes.peek().get(this.compilationScopes.peek().size() - 1); } /** @@ -105,13 +106,14 @@ public class CodeFlow implements Opcodes { } } + /** * Insert any necessary cast and value call to convert from a boxed type to a * primitive value * @param mv the method visitor into which instructions should be inserted * @param ch the primitive type desired as output - * @param isObject indicates whether the type on the stack is being thought of as - * Object (and so requires a cast) + * @param isObject indicates whether the type on the stack is being thought of + * as Object (and so requires a cast) */ public static void insertUnboxInsns(MethodVisitor mv, char ch, boolean isObject) { switch (ch) { @@ -179,14 +181,14 @@ public class CodeFlow implements Opcodes { */ public static String createSignatureDescriptor(Method method) { Class[] params = method.getParameterTypes(); - StringBuilder s = new StringBuilder(); - s.append("("); - for (int i = 0, max = params.length; i < max; i++) { - s.append(toJVMDescriptor(params[i])); + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (Class param : params) { + sb.append(toJVMDescriptor(param)); } - s.append(")"); - s.append(toJVMDescriptor(method.getReturnType())); - return s.toString(); + sb.append(")"); + sb.append(toJVMDescriptor(method.getReturnType())); + return sb.toString(); } /** @@ -199,13 +201,13 @@ public class CodeFlow implements Opcodes { */ public static String createSignatureDescriptor(Constructor ctor) { Class[] params = ctor.getParameterTypes(); - StringBuilder s = new StringBuilder(); - s.append("("); - for (int i = 0, max = params.length; i < max; i++) { - s.append(toJVMDescriptor(params[i])); + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (Class param : params) { + sb.append(toJVMDescriptor(param)); } - s.append(")V"); - return s.toString(); + sb.append(")V"); + return sb.toString(); } /** @@ -213,7 +215,6 @@ public class CodeFlow implements Opcodes { * used in the compilation process, this is the one the JVM wants, so this one * includes any necessary trailing semicolon (e.g. Ljava/lang/String; rather than * Ljava/lang/String) - * * @param clazz a class * @return the JVM descriptor for the class */ @@ -262,39 +263,39 @@ public class CodeFlow implements Opcodes { } /** - * Determine the descriptor for an object instance (or null). - * @param value an object (possibly null) - * @return the type descriptor for the object (descriptor is "Ljava/lang/Object" for - * null value) + * Determine the descriptor for an object instance (or {@code null}). + * @param value an object (possibly {@code null}) + * @return the type descriptor for the object + * (descriptor is "Ljava/lang/Object" for {@code null} value) */ public static String toDescriptorFromObject(Object value) { if (value == null) { return "Ljava/lang/Object"; - } else { + } + else { return toDescriptor(value.getClass()); } } /** * @param descriptor type descriptor - * @return true if the descriptor is for a boolean primitive or boolean reference type + * @return {@code true} if the descriptor is for a boolean primitive or boolean reference type */ public static boolean isBooleanCompatible(String descriptor) { - return descriptor != null - && (descriptor.equals("Z") || descriptor.equals("Ljava/lang/Boolean")); + return (descriptor != null && (descriptor.equals("Z") || descriptor.equals("Ljava/lang/Boolean"))); } /** * @param descriptor type descriptor - * @return true if the descriptor is for a primitive type + * @return {@code true} if the descriptor is for a primitive type */ public static boolean isPrimitive(String descriptor) { - return descriptor!=null && descriptor.length()==1; + return (descriptor != null && descriptor.length() == 1); } /** * @param descriptor the descriptor for a possible primitive array - * @return true if the descriptor is for a primitive array (e.g. "[[I") + * @return {@code true} if the descriptor is for a primitive array (e.g. "[[I") */ public static boolean isPrimitiveArray(String descriptor) { boolean primitive = true; @@ -312,14 +313,13 @@ public class CodeFlow implements Opcodes { /** * Determine if boxing/unboxing can get from one type to the other. Assumes at least * one of the types is in boxed form (i.e. single char descriptor). - * - * @return true if it is possible to get (via boxing) from one descriptor to the other + * @return {@code true} if it is possible to get (via boxing) from one descriptor to the other */ public static boolean areBoxingCompatible(String desc1, String desc2) { if (desc1.equals(desc2)) { return true; } - if (desc1.length()==1) { + if (desc1.length() == 1) { if (desc1.equals("D")) { return desc2.equals("Ljava/lang/Double"); } @@ -336,7 +336,7 @@ public class CodeFlow implements Opcodes { return desc2.equals("Ljava/lang/Boolean"); } } - else if (desc2.length()==1) { + else if (desc2.length() == 1) { if (desc2.equals("D")) { return desc1.equals("Ljava/lang/Double"); } @@ -361,14 +361,14 @@ public class CodeFlow implements Opcodes { * compilation process only (currently) supports certain number types. These are * double, float, long and int. * @param descriptor the descriptor for a type - * @return true if the descriptor is for a supported numeric type or boolean + * @return {@code true} if the descriptor is for a supported numeric type or boolean */ public static boolean isPrimitiveOrUnboxableSupportedNumberOrBoolean(String descriptor) { - if (descriptor==null) { + if (descriptor == null) { return false; } - if (descriptor.length()==1) { - return "DFJZI".indexOf(descriptor.charAt(0))!=-1; + if (descriptor.length( )== 1) { + return ("DFJZI".indexOf(descriptor.charAt(0)) != -1); } if (descriptor.startsWith("Ljava/lang/")) { if (descriptor.equals("Ljava/lang/Double") || descriptor.equals("Ljava/lang/Integer") || @@ -385,14 +385,14 @@ public class CodeFlow implements Opcodes { * process only (currently) supports certain number types. These are double, float, * long and int. * @param descriptor the descriptor for a type - * @return true if the descriptor is for a supported numeric type + * @return {@code true} if the descriptor is for a supported numeric type */ public static boolean isPrimitiveOrUnboxableSupportedNumber(String descriptor) { - if (descriptor==null) { + if (descriptor == null) { return false; } - if (descriptor.length()==1) { - return "DFJI".indexOf(descriptor.charAt(0))!=-1; + if (descriptor.length() == 1) { + return ("DFJI".indexOf(descriptor.charAt(0)) != -1); } if (descriptor.startsWith("Ljava/lang/")) { if (descriptor.equals("Ljava/lang/Double") || descriptor.equals("Ljava/lang/Integer") || @@ -404,12 +404,11 @@ public class CodeFlow implements Opcodes { } /** - * @param descriptor a descriptor for a type that should have a primitive - * representation + * @param descriptor a descriptor for a type that should have a primitive representation * @return the single character descriptor for a primitive input descriptor */ public static char toPrimitiveTargetDesc(String descriptor) { - if (descriptor.length()==1) { + if (descriptor.length() == 1) { return descriptor.charAt(0); } if (descriptor.equals("Ljava/lang/Double")) { @@ -438,13 +437,13 @@ public class CodeFlow implements Opcodes { * @param descriptor the descriptor of the type to cast to */ public static void insertCheckCast(MethodVisitor mv, String descriptor) { - if (descriptor.length()!=1) { - if (descriptor.charAt(0)=='[') { - if (CodeFlow.isPrimitiveArray(descriptor)) { + if (descriptor.length() != 1) { + if (descriptor.charAt(0) == '[') { + if (isPrimitiveArray(descriptor)) { mv.visitTypeInsn(CHECKCAST, descriptor); } else { - mv.visitTypeInsn(CHECKCAST, descriptor+";"); + mv.visitTypeInsn(CHECKCAST, descriptor + ";"); } } else { @@ -557,14 +556,14 @@ public class CodeFlow implements Opcodes { } else { if (name.charAt(0) != '[') { - return new StringBuilder("L").append(type.getName().replace('.', '/')).toString(); + return "L" + type.getName().replace('.', '/'); } else { if (name.endsWith(";")) { return name.substring(0, name.length() - 1).replace('.', '/'); } else { - return name; // array has primitive component type + return name; // array has primitive component type } } } @@ -595,7 +594,7 @@ public class CodeFlow implements Opcodes { int typesCount = types.length; String[] descriptors = new String[typesCount]; for (int p = 0; p < typesCount; p++) { - descriptors[p] = CodeFlow.toDescriptor(types[p]); + descriptors[p] = toDescriptor(types[p]); } return descriptors; } diff --git a/spring-expression/src/main/java/org/springframework/expression/CompilablePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/CompilablePropertyAccessor.java similarity index 64% rename from spring-expression/src/main/java/org/springframework/expression/CompilablePropertyAccessor.java rename to spring-expression/src/main/java/org/springframework/expression/spel/CompilablePropertyAccessor.java index 35caa15700b..6294a51b13c 100644 --- a/spring-expression/src/main/java/org/springframework/expression/CompilablePropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/CompilablePropertyAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2002-2014 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. @@ -14,13 +14,11 @@ * limitations under the License. */ -package org.springframework.expression; +package org.springframework.expression.spel; import org.springframework.asm.MethodVisitor; import org.springframework.asm.Opcodes; -import org.springframework.expression.spel.ast.PropertyOrFieldReference; -import org.springframework.expression.spel.standard.CodeFlow; - +import org.springframework.expression.PropertyAccessor; /** * A compilable property accessor is able to generate bytecode that represents @@ -33,21 +31,22 @@ import org.springframework.expression.spel.standard.CodeFlow; public interface CompilablePropertyAccessor extends PropertyAccessor, Opcodes { /** - * @return true if this property accessor is currently suitable for compilation. + * Return {@code true} if this property accessor is currently suitable for compilation. */ boolean isCompilable(); /** - * Generate the bytecode the performs the access operation into the specified MethodVisitor using - * context information from the codeflow where necessary. - * @param propertyReference the property reference for which code is being generated + * Return the type of the accessed property - may only be known once an access has occurred. + */ + Class getPropertyType(); + + /** + * Generate the bytecode the performs the access operation into the specified MethodVisitor + * using context information from the codeflow where necessary. + * @param propertyName the name of the property * @param mv the Asm method visitor into which code should be generated * @param codeflow the current state of the expression compiler */ - void generateCode(PropertyOrFieldReference propertyReference, MethodVisitor mv, CodeFlow codeflow); + void generateCode(String propertyName, MethodVisitor mv, CodeFlow codeflow); - /** - * @return the type of the accessed property - may only be known once an access has occurred. - */ - Class getPropertyType(); } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/CompiledExpression.java b/spring-expression/src/main/java/org/springframework/expression/spel/CompiledExpression.java index 6a2f88e6975..5ec0ee502c0 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/CompiledExpression.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/CompiledExpression.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2002-2014 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. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -30,8 +30,8 @@ import org.springframework.expression.EvaluationException; public abstract class CompiledExpression { /** - * Subclasses of CompiledExpression generated by SpelCompiler will provide an implementation of - * this method. + * Subclasses of CompiledExpression generated by SpelCompiler will provide an + * implementation of this method. */ public abstract Object getValue(Object target, EvaluationContext context) throws EvaluationException; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/SpelCompilerMode.java b/spring-expression/src/main/java/org/springframework/expression/spel/SpelCompilerMode.java index da53d058dee..adf8fbe68d4 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/SpelCompilerMode.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/SpelCompilerMode.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2002-2014 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. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -24,22 +24,24 @@ package org.springframework.expression.spel; * @since 4.1 */ public enum SpelCompilerMode { - /** + + /** * The compiler is switched off, this is the default. */ - off, - + OFF, + /** * In immediate mode, expressions are compiled as soon as possible (usually after 1 interpreted run). * If a compiled expression fails it will throw an exception to the caller. */ - immediate, - + IMMEDIATE, + /** * In mixed mode, expression evaluate silently switches between interpreted and compiled over time. * After a number of runs the expression gets compiled. If it later fails (possibly due to inferred * type information changing) then that will be caught internally and the system switches back to * interpreted mode. It may subsequently compile it again later. */ - mixed -} \ No newline at end of file + MIXED + +} diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java b/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java index 7d5b4e2be22..cbefcc8cc6c 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java @@ -30,24 +30,42 @@ import org.springframework.core.SpringProperties; */ public class SpelParserConfiguration { - private final boolean autoGrowNullReferences; - - private final boolean autoGrowCollections; - - private static SpelCompilerMode defaultCompilerMode = SpelCompilerMode.off; - - private SpelCompilerMode compilerMode; - - private final int maximumAutoGrowSize; + private static final SpelCompilerMode defaultCompilerMode; static { String compilerMode = SpringProperties.getProperty("spring.expression.compiler.mode"); - if (compilerMode != null) { - defaultCompilerMode = SpelCompilerMode.valueOf(compilerMode.toLowerCase()); - // System.out.println("SpelCompiler: switched to "+defaultCompilerMode+" mode"); - } + defaultCompilerMode = (compilerMode != null ? + SpelCompilerMode.valueOf(compilerMode.toUpperCase()) : SpelCompilerMode.OFF); } - + + + private final SpelCompilerMode compilerMode; + + private final ClassLoader compilerClassLoader; + + private final boolean autoGrowNullReferences; + + private final boolean autoGrowCollections; + + private final int maximumAutoGrowSize; + + + /** + * Create a new {@link SpelParserConfiguration} instance with default settings. + */ + public SpelParserConfiguration() { + this(null, null, false, false, Integer.MAX_VALUE); + } + + /** + * Create a new {@link SpelParserConfiguration} instance. + * @param compilerMode the compiler mode for the parser + * @param compilerClassLoader the ClassLoader to use as the basis for expression compilation + */ + public SpelParserConfiguration(SpelCompilerMode compilerMode, ClassLoader compilerClassLoader) { + this(compilerMode, compilerClassLoader, false, false, Integer.MAX_VALUE); + } + /** * Create a new {@link SpelParserConfiguration} instance. * @param autoGrowNullReferences if null references should automatically grow @@ -55,7 +73,7 @@ public class SpelParserConfiguration { * @see #SpelParserConfiguration(boolean, boolean, int) */ public SpelParserConfiguration(boolean autoGrowNullReferences, boolean autoGrowCollections) { - this(autoGrowNullReferences, autoGrowCollections, Integer.MAX_VALUE); + this(null, null, autoGrowNullReferences, autoGrowCollections, Integer.MAX_VALUE); } /** @@ -65,19 +83,28 @@ public class SpelParserConfiguration { * @param maximumAutoGrowSize the maximum size that the collection can auto grow */ public SpelParserConfiguration(boolean autoGrowNullReferences, boolean autoGrowCollections, int maximumAutoGrowSize) { + this(null, null, autoGrowNullReferences, autoGrowCollections, maximumAutoGrowSize); + } + + /** + * Create a new {@link SpelParserConfiguration} instance. + * @param compilerMode the compiler mode that parsers using this configuration object should use + * @param compilerClassLoader the ClassLoader to use as the basis for expression compilation + * @param autoGrowNullReferences if null references should automatically grow + * @param autoGrowCollections if collections should automatically grow + * @param maximumAutoGrowSize the maximum size that the collection can auto grow + */ + public SpelParserConfiguration(SpelCompilerMode compilerMode, ClassLoader compilerClassLoader, + boolean autoGrowNullReferences, boolean autoGrowCollections, int maximumAutoGrowSize) { + + this.compilerMode = (compilerMode != null ? compilerMode : defaultCompilerMode); + this.compilerClassLoader = compilerClassLoader; this.autoGrowNullReferences = autoGrowNullReferences; this.autoGrowCollections = autoGrowCollections; this.maximumAutoGrowSize = maximumAutoGrowSize; - this.compilerMode = defaultCompilerMode; - } - - /** - * @param compilerMode the compiler mode that parsers using this configuration object should use - */ - public void setCompilerMode(SpelCompilerMode compilerMode) { - this.compilerMode = compilerMode; } + /** * @return the configuration mode for parsers using this configuration object */ @@ -85,6 +112,13 @@ public class SpelParserConfiguration { return this.compilerMode; } + /** + * @return the ClassLoader to use as the basis for expression compilation + */ + public ClassLoader getCompilerClassLoader() { + return this.compilerClassLoader; + } + /** * @return {@code true} if {@code null} references should be automatically grown */ diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/BooleanLiteral.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/BooleanLiteral.java index abd9f89a827..827e01c50ea 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/BooleanLiteral.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/BooleanLiteral.java @@ -16,7 +16,7 @@ package org.springframework.expression.spel.ast; import org.springframework.asm.MethodVisitor; -import org.springframework.expression.spel.standard.CodeFlow; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.support.BooleanTypedValue; /** diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java index 7973fe457bf..a540ac9c28d 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java @@ -19,9 +19,9 @@ package org.springframework.expression.spel.ast; import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationException; import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelEvaluationException; -import org.springframework.expression.spel.standard.CodeFlow; /** * Represents a DOT separated expression sequence, such as 'property1.property2.methodOne()' diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java index 33bf269084e..3b08361cde0 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java @@ -33,11 +33,11 @@ import org.springframework.expression.EvaluationException; import org.springframework.expression.TypeConverter; import org.springframework.expression.TypedValue; import org.springframework.expression.common.ExpressionUtils; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; import org.springframework.expression.spel.SpelNode; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.ReflectiveConstructorExecutor; /** diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java index 5677fcd7327..5d9d8987a8c 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java @@ -20,8 +20,8 @@ import org.springframework.asm.Label; import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationException; import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; -import org.springframework.expression.spel.standard.CodeFlow; /** * Represents the elvis operator ?:. For an expression "a?:b" if a is not null, the value diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/FloatLiteral.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/FloatLiteral.java index e11bbf37da8..0f0dc5d8c80 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/FloatLiteral.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/FloatLiteral.java @@ -18,7 +18,7 @@ package org.springframework.expression.spel.ast; import org.springframework.asm.MethodVisitor; import org.springframework.expression.TypedValue; -import org.springframework.expression.spel.standard.CodeFlow; +import org.springframework.expression.spel.CodeFlow; /** * Expression language AST node that represents a float literal. diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java index f1e39a6e132..f0fe7d4e8ed 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java @@ -25,10 +25,10 @@ import org.springframework.core.convert.TypeDescriptor; import org.springframework.expression.EvaluationException; import org.springframework.expression.TypeConverter; import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.ReflectionHelper; import org.springframework.util.ReflectionUtils; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java index ad5774a6d3c..6ddfe998ce1 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java @@ -32,10 +32,10 @@ import org.springframework.expression.EvaluationException; import org.springframework.expression.PropertyAccessor; import org.springframework.expression.TypeConverter; import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.ReflectivePropertyAccessor; /** diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java index 4e2c77f553a..1f4436ecacc 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java @@ -17,7 +17,7 @@ package org.springframework.expression.spel.ast; import org.springframework.asm.MethodVisitor; import org.springframework.expression.TypedValue; -import org.springframework.expression.spel.standard.CodeFlow; +import org.springframework.expression.spel.CodeFlow; /** * Expression language AST node that represents an integer literal. diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/LongLiteral.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/LongLiteral.java index 6dd102e868a..d59f6443d17 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/LongLiteral.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/LongLiteral.java @@ -18,7 +18,7 @@ package org.springframework.expression.spel.ast; import org.springframework.asm.MethodVisitor; import org.springframework.expression.TypedValue; -import org.springframework.expression.spel.standard.CodeFlow; +import org.springframework.expression.spel.CodeFlow; /** * Expression language AST node that represents a long integer literal. diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java index cfe1b7109a2..fdf6e46541f 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java @@ -32,10 +32,10 @@ import org.springframework.expression.ExpressionInvocationTargetException; import org.springframework.expression.MethodExecutor; import org.springframework.expression.MethodResolver; import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.ReflectiveMethodExecutor; import org.springframework.expression.spel.support.ReflectiveMethodResolver; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/NullLiteral.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/NullLiteral.java index 483665d5fc2..b3b9483654f 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/NullLiteral.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/NullLiteral.java @@ -18,7 +18,7 @@ package org.springframework.expression.spel.ast; import org.springframework.asm.MethodVisitor; import org.springframework.expression.TypedValue; -import org.springframework.expression.spel.standard.CodeFlow; +import org.springframework.expression.spel.CodeFlow; /** * Expression language AST node that represents null. diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpAnd.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpAnd.java index fb2a6daefc8..204b905aa3a 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpAnd.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpAnd.java @@ -20,10 +20,10 @@ import org.springframework.asm.Label; import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationException; import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.BooleanTypedValue; /** diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDivide.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDivide.java index 2b144e30b10..7f7c13ac9f4 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDivide.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDivide.java @@ -16,16 +16,15 @@ package org.springframework.expression.spel.ast; -import org.springframework.asm.MethodVisitor; - import java.math.BigDecimal; import java.math.RoundingMode; +import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationException; import org.springframework.expression.Operation; import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.util.NumberUtils; /** diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpEQ.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpEQ.java index a3aa5dcc6f5..e71ad7eca1d 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpEQ.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpEQ.java @@ -19,8 +19,8 @@ package org.springframework.expression.spel.ast; import org.springframework.asm.Label; import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.BooleanTypedValue; /** diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGE.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGE.java index 48b43df7188..59f9302d6c5 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGE.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGE.java @@ -15,11 +15,12 @@ */ package org.springframework.expression.spel.ast; -import org.springframework.asm.MethodVisitor; import java.math.BigDecimal; + +import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.util.NumberUtils; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGT.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGT.java index 2780ba96e88..fc55472fe41 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGT.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGT.java @@ -16,11 +16,12 @@ package org.springframework.expression.spel.ast; -import org.springframework.asm.MethodVisitor; import java.math.BigDecimal; + +import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.util.NumberUtils; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLE.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLE.java index 98fd4ecbbec..1680e121e40 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLE.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLE.java @@ -16,11 +16,12 @@ package org.springframework.expression.spel.ast; -import org.springframework.asm.MethodVisitor; import java.math.BigDecimal; + +import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.util.NumberUtils; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLT.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLT.java index ee36f1320fe..8fee088a6ee 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLT.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLT.java @@ -16,11 +16,12 @@ package org.springframework.expression.spel.ast; -import org.springframework.asm.MethodVisitor; import java.math.BigDecimal; + +import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.util.NumberUtils; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMinus.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMinus.java index acbc5deca0c..615f4b8084d 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMinus.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMinus.java @@ -16,15 +16,14 @@ package org.springframework.expression.spel.ast; -import org.springframework.asm.MethodVisitor; - import java.math.BigDecimal; +import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationException; import org.springframework.expression.Operation; import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.util.NumberUtils; /** diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java index ff0c967d2df..d4722964a10 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java @@ -16,15 +16,14 @@ package org.springframework.expression.spel.ast; -import org.springframework.asm.MethodVisitor; - import java.math.BigDecimal; +import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationException; import org.springframework.expression.Operation; import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.util.NumberUtils; /** diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpNE.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpNE.java index 7af16b550fc..a92159d746a 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpNE.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpNE.java @@ -19,8 +19,8 @@ package org.springframework.expression.spel.ast; import org.springframework.asm.Label; import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.BooleanTypedValue; /** diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpOr.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpOr.java index b7213c374fb..45e6b03ceeb 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpOr.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpOr.java @@ -19,10 +19,10 @@ package org.springframework.expression.spel.ast; import org.springframework.asm.Label; import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.BooleanTypedValue; /** diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java index 74a8ad93da1..843676aea75 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java @@ -16,17 +16,16 @@ package org.springframework.expression.spel.ast; -import org.springframework.asm.MethodVisitor; - import java.math.BigDecimal; +import org.springframework.asm.MethodVisitor; import org.springframework.core.convert.TypeDescriptor; import org.springframework.expression.EvaluationException; import org.springframework.expression.Operation; import org.springframework.expression.TypeConverter; import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.util.Assert; import org.springframework.util.NumberUtils; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java index 0e7bd63f67a..0e7e32b2115 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java @@ -16,12 +16,11 @@ package org.springframework.expression.spel.ast; -import org.springframework.asm.Label; -import org.springframework.asm.MethodVisitor; -import org.springframework.expression.spel.standard.CodeFlow; - import java.math.BigDecimal; +import org.springframework.asm.Label; +import org.springframework.asm.MethodVisitor; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; import org.springframework.util.ClassUtils; import org.springframework.util.NumberUtils; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorInstanceof.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorInstanceof.java index ed9c403440b..002a90a9d92 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorInstanceof.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorInstanceof.java @@ -20,10 +20,10 @@ import org.springframework.asm.MethodVisitor; import org.springframework.asm.Type; import org.springframework.expression.EvaluationException; import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.BooleanTypedValue; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorNot.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorNot.java index f266b72cfc8..a24ff618cf2 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorNot.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorNot.java @@ -19,10 +19,10 @@ package org.springframework.expression.spel.ast; import org.springframework.asm.Label; import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.BooleanTypedValue; /** diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java index 097b93f03aa..94d3436e22b 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -24,15 +24,15 @@ import java.util.Map; import org.springframework.asm.MethodVisitor; import org.springframework.core.convert.TypeDescriptor; import org.springframework.expression.AccessException; -import org.springframework.expression.CompilablePropertyAccessor; import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationException; import org.springframework.expression.PropertyAccessor; import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.CodeFlow; +import org.springframework.expression.spel.CompilablePropertyAccessor; import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.ReflectivePropertyAccessor; /** @@ -331,19 +331,14 @@ public class PropertyOrFieldReference extends SpelNodeImpl { @Override public boolean isCompilable() { - if (this.cachedReadAccessor == null) { - return false; - } - if (this.cachedReadAccessor instanceof CompilablePropertyAccessor) { - return ((CompilablePropertyAccessor)this.cachedReadAccessor).isCompilable(); - } - return false; + return (this.cachedReadAccessor instanceof CompilablePropertyAccessor && + ((CompilablePropertyAccessor) this.cachedReadAccessor).isCompilable()); } @Override - public void generateCode(MethodVisitor mv,CodeFlow codeflow) { - ((CompilablePropertyAccessor)this.cachedReadAccessor).generateCode(this, mv, codeflow); - codeflow.pushDescriptor(exitTypeDescriptor); + public void generateCode(MethodVisitor mv, CodeFlow codeflow) { + ((CompilablePropertyAccessor) this.cachedReadAccessor).generateCode(this.name, mv, codeflow); + codeflow.pushDescriptor(this.exitTypeDescriptor); } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/RealLiteral.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/RealLiteral.java index 6a03106ef0b..273d47697d7 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/RealLiteral.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/RealLiteral.java @@ -18,7 +18,7 @@ package org.springframework.expression.spel.ast; import org.springframework.asm.MethodVisitor; import org.springframework.expression.TypedValue; -import org.springframework.expression.spel.standard.CodeFlow; +import org.springframework.expression.spel.CodeFlow; /** * Expression language AST node that represents a real literal. diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.java index 798923a2b86..36363c319a9 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.java @@ -21,11 +21,11 @@ import org.springframework.asm.Opcodes; import org.springframework.expression.EvaluationException; import org.springframework.expression.TypedValue; import org.springframework.expression.common.ExpressionUtils; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; import org.springframework.expression.spel.SpelNode; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.util.Assert; @@ -58,6 +58,7 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes { */ protected String exitTypeDescriptor; + public SpelNodeImpl(int pos, SpelNodeImpl... operands) { this.pos = pos; // pos combines start and end so can never be zero because tokens cannot be zero length @@ -184,7 +185,6 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes { * Check whether a node can be compiled to bytecode. The reasoning in each node may * be different but will typically involve checking whether the exit type descriptor * of the node is known and any relevant child nodes are compilable. - * * @return true if this node can be compiled to bytecode */ public boolean isCompilable() { @@ -196,7 +196,6 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes { * the current expression being compiled is available in the codeflow object. For * example it will include information about the type of the object currently * on the stack. - * * @param mv the ASM MethodVisitor into which code should be generated * @param codeflow a context object with info about what is on the stack */ diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/StringLiteral.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/StringLiteral.java index 46f46da3974..6a1aabd9289 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/StringLiteral.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/StringLiteral.java @@ -18,7 +18,7 @@ package org.springframework.expression.spel.ast; import org.springframework.asm.MethodVisitor; import org.springframework.expression.TypedValue; -import org.springframework.expression.spel.standard.CodeFlow; +import org.springframework.expression.spel.CodeFlow; /** * Expression language AST node that represents a string literal. diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java index eac2af4f9e3..96868e25b0b 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java @@ -20,10 +20,10 @@ import org.springframework.asm.Label; import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationException; import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; -import org.springframework.expression.spel.standard.CodeFlow; /** * Represents a ternary expression, for example: "someCheck()?true:false". diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/TypeReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/TypeReference.java index 963658294c6..6b7c2c1f886 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/TypeReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/TypeReference.java @@ -22,8 +22,8 @@ import org.springframework.asm.MethodVisitor; import org.springframework.asm.Type; import org.springframework.expression.EvaluationException; import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; -import org.springframework.expression.spel.standard.CodeFlow; /** * Represents a reference to a type, for example "T(String)" or "T(com.somewhere.Foo)" diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/VariableReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/VariableReference.java index 6cbe3e1e30d..0bb8654d2d8 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/VariableReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/VariableReference.java @@ -19,9 +19,9 @@ package org.springframework.expression.spel.ast; import org.springframework.asm.MethodVisitor; import org.springframework.expression.EvaluationContext; import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.SpelEvaluationException; -import org.springframework.expression.spel.standard.CodeFlow; /** * Represents a variable reference, eg. #someVar. Note this is different to a *local* diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java index c459937fefb..9be0b722ac7 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -29,7 +29,48 @@ import org.springframework.expression.spel.InternalParseException; import org.springframework.expression.spel.SpelMessage; import org.springframework.expression.spel.SpelParseException; import org.springframework.expression.spel.SpelParserConfiguration; -import org.springframework.expression.spel.ast.*; +import org.springframework.expression.spel.ast.Assign; +import org.springframework.expression.spel.ast.BeanReference; +import org.springframework.expression.spel.ast.BooleanLiteral; +import org.springframework.expression.spel.ast.CompoundExpression; +import org.springframework.expression.spel.ast.ConstructorReference; +import org.springframework.expression.spel.ast.Elvis; +import org.springframework.expression.spel.ast.FunctionReference; +import org.springframework.expression.spel.ast.Identifier; +import org.springframework.expression.spel.ast.Indexer; +import org.springframework.expression.spel.ast.InlineList; +import org.springframework.expression.spel.ast.Literal; +import org.springframework.expression.spel.ast.MethodReference; +import org.springframework.expression.spel.ast.NullLiteral; +import org.springframework.expression.spel.ast.OpAnd; +import org.springframework.expression.spel.ast.OpDec; +import org.springframework.expression.spel.ast.OpDivide; +import org.springframework.expression.spel.ast.OpEQ; +import org.springframework.expression.spel.ast.OpGE; +import org.springframework.expression.spel.ast.OpGT; +import org.springframework.expression.spel.ast.OpInc; +import org.springframework.expression.spel.ast.OpLE; +import org.springframework.expression.spel.ast.OpLT; +import org.springframework.expression.spel.ast.OpMinus; +import org.springframework.expression.spel.ast.OpModulus; +import org.springframework.expression.spel.ast.OpMultiply; +import org.springframework.expression.spel.ast.OpNE; +import org.springframework.expression.spel.ast.OpOr; +import org.springframework.expression.spel.ast.OpPlus; +import org.springframework.expression.spel.ast.OperatorBetween; +import org.springframework.expression.spel.ast.OperatorInstanceof; +import org.springframework.expression.spel.ast.OperatorMatches; +import org.springframework.expression.spel.ast.OperatorNot; +import org.springframework.expression.spel.ast.OperatorPower; +import org.springframework.expression.spel.ast.Projection; +import org.springframework.expression.spel.ast.PropertyOrFieldReference; +import org.springframework.expression.spel.ast.QualifiedIdentifier; +import org.springframework.expression.spel.ast.Selection; +import org.springframework.expression.spel.ast.SpelNodeImpl; +import org.springframework.expression.spel.ast.StringLiteral; +import org.springframework.expression.spel.ast.Ternary; +import org.springframework.expression.spel.ast.TypeReference; +import org.springframework.expression.spel.ast.VariableReference; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -84,13 +125,13 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { this.constructedNodes.clear(); SpelNodeImpl ast = eatExpression(); if (moreTokens()) { - throw new SpelParseException(peekToken().startpos,SpelMessage.MORE_INPUT,toString(nextToken())); + throw new SpelParseException(peekToken().startpos, SpelMessage.MORE_INPUT, toString(nextToken())); } Assert.isTrue(this.constructedNodes.isEmpty()); return new SpelExpression(expressionString, ast, this.configuration); } - catch (InternalParseException ipe) { - throw ipe.getCause(); + catch (InternalParseException ex) { + throw ex.getCause(); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelCompiler.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelCompiler.java index 5d32b6395db..12cd18a1cfd 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelCompiler.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelCompiler.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2002-2014 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. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,26 +20,30 @@ import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; -import java.util.Collections; import java.util.Map; -import java.util.WeakHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.asm.ClassWriter; import org.springframework.asm.MethodVisitor; import org.springframework.asm.Opcodes; import org.springframework.expression.Expression; +import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.CompiledExpression; import org.springframework.expression.spel.SpelParserConfiguration; import org.springframework.expression.spel.ast.SpelNodeImpl; import org.springframework.util.ClassUtils; +import org.springframework.util.ConcurrentReferenceHashMap; /** * A SpelCompiler will take a regular parsed expression and create (and load) a class * containing byte code that does the same thing as that expression. The compiled form of * an expression will evaluate far faster than the interpreted form. - *

- * The SpelCompiler is not currently handling all expression types but covers many of the - * common cases. The framework is extensible to cover more cases in the future. For + * + *

The SpelCompiler is not currently handling all expression types but covers many of + * the common cases. The framework is extensible to cover more cases in the future. For * absolute maximum speed there is *no checking* in the compiled code. The compiled * version of the expression uses information learned during interpreted runs of the * expression when it generates the byte code. For example if it knows that a particular @@ -48,64 +52,40 @@ import org.springframework.util.ClassUtils; * performance but should the dereference result in something other than a map, the * compiled expression will fail - like a ClassCastException would occur if passing data * of an unexpected type in a regular Java program. - *

- * Due to the lack of checking there are likely some expressions that should never be + * + *

Due to the lack of checking there are likely some expressions that should never be * compiled, for example if an expression is continuously dealing with different types of * data. Due to these cases the compiler is something that must be selectively turned on * for an associated SpelExpressionParser (through the {@link SpelParserConfiguration} * object), it is not on by default. - *

- * Individual expressions can be compiled by calling - * SpelCompiler.compile(expression). + * + *

Individual expressions can be compiled by calling {@code SpelCompiler.compile(expression)}. * * @author Andy Clement * @since 4.1 */ public class SpelCompiler implements Opcodes { - // Default number of times to interpret an expression before compiling it - private static int DEFAULT_INTERPRETED_COUNT_THRESHOLD = 100; - - // Once an expression is evaluated the threshold number of times, it will be a candidate for compilation - public static int interpretedCountThreshold = DEFAULT_INTERPRETED_COUNT_THRESHOLD; - - // Useful for debugging - public static final boolean verbose = false; + 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 Map compilers = Collections.synchronizedMap(new WeakHashMap()); + private static final Map compilers = + new ConcurrentReferenceHashMap(); - // The child classloader used to load the compiled expression classes - private ChildClassLoader ccl; + + // The child ClassLoader used to load the compiled expression classes + private final ChildClassLoader ccl; // counter suffix for generated classes within this SpelCompiler instance - private int suffixId; + private final AtomicInteger suffixId = new AtomicInteger(1); - /** - * Factory method for compiler instances. The returned SpelCompiler will - * attach a class loader as the child of the default class loader and this - * child will be used to load compiled expressions. - * - * @return a SpelCompiler instance - */ - public static SpelCompiler getCompiler() { - ClassLoader classloader = ClassUtils.getDefaultClassLoader(); - synchronized (compilers) { - SpelCompiler compiler = compilers.get(classloader); - if (compiler == null) { - compiler = new SpelCompiler(classloader); - compilers.put(classloader,compiler); - } - return compiler; - } - } private SpelCompiler(ClassLoader classloader) { this.ccl = new ChildClassLoader(classloader); - this.suffixId = 1; } + /** * Attempt compilation of the supplied expression. A check is * made to see if it is compilable before compilation proceeds. The @@ -118,31 +98,27 @@ public class SpelCompiler implements Opcodes { */ public CompiledExpression compile(SpelNodeImpl expression) { if (expression.isCompilable()) { - if (verbose) { - System.out.println("SpEL: compiling " + expression.toStringAST()); + if (logger.isDebugEnabled()) { + logger.debug("SpEL: compiling " + expression.toStringAST()); } Class clazz = createExpressionClass(expression); try { - CompiledExpression instance = clazz.newInstance(); - return instance; + return clazz.newInstance(); } - catch (InstantiationException ie) { - ie.printStackTrace(); - } - catch (IllegalAccessException iae) { - iae.printStackTrace(); + catch (Exception ex) { + throw new IllegalStateException("Failed to instantiate CompiledExpression", ex); } } else { - if (verbose) { - System.out.println("SpEL: unable to compile " + expression.toStringAST()); + if (logger.isDebugEnabled()) { + logger.debug("SpEL: unable to compile " + expression.toStringAST()); } } return null; } - private synchronized int getNextSuffix() { - return suffixId++; + private int getNextSuffix() { + return this.suffixId.incrementAndGet(); } /** @@ -152,7 +128,6 @@ public class SpelCompiler implements Opcodes { */ @SuppressWarnings("unchecked") private Class createExpressionClass(SpelNodeImpl expressionToCompile) { - // Create class outline 'spel/ExNNN extends org.springframework.expression.spel.CompiledExpression' String clazzName = "spel/Ex" + getNextSuffix(); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES); @@ -179,7 +154,7 @@ public class SpelCompiler implements Opcodes { expressionToCompile.generateCode(mv,codeflow); CodeFlow.insertBoxIfNecessary(mv,codeflow.lastDescriptor()); - if (codeflow.lastDescriptor() == "V") { + if ("V".equals(codeflow.lastDescriptor())) { mv.visitInsn(ACONST_NULL); } mv.visitInsn(ARETURN); @@ -190,44 +165,79 @@ public class SpelCompiler implements Opcodes { byte[] data = cw.toByteArray(); // TODO need to make this conditionally occur based on a debug flag // dump(expressionToCompile.toStringAST(), clazzName, data); - Class clazz = (Class) ccl.defineClass(clazzName.replaceAll("/","."),data); - return clazz; + return (Class) ccl.defineClass(clazzName.replaceAll("/","."),data); + } + + + /** + * Factory method for compiler instances. The returned SpelCompiler will + * attach a class loader as the child of the given class loader and this + * child will be used to load compiled expressions. + * @param classLoader the ClassLoader to use as the basis for compilation + * @return a corresponding SpelCompiler instance + */ + public static SpelCompiler getCompiler(ClassLoader classLoader) { + ClassLoader clToUse = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader()); + synchronized (compilers) { + SpelCompiler compiler = compilers.get(clToUse); + if (compiler == null) { + compiler = new SpelCompiler(clToUse); + compilers.put(clToUse, compiler); + } + return compiler; + } } /** - * For debugging purposes, dump the specified byte code into a file on the disk. Not - * yet hooked in, needs conditionally calling based on a sys prop. - * + * 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 + */ + public static boolean compile(Expression expression) { + return (expression instanceof SpelExpression && ((SpelExpression) expression).compileExpression()); + } + + /** + * Request to revert to the interpreter for expression evaluation. Any compiled form + * is discarded but can be recreated by later recompiling again. + * @param expression the expression + */ + public static void revertToInterpreted(Expression expression) { + if (expression instanceof SpelExpression) { + ((SpelExpression) expression).revertToInterpreted(); + } + } + + /** + * For debugging purposes, dump the specified byte code into a file on the disk. + * Not yet hooked in, needs conditionally calling based on a sys prop. * @param expressionText the text of the expression compiled * @param name the name of the class being used for the compiled expression * @param bytecode the bytecode for the generated class */ @SuppressWarnings("unused") private static void dump(String expressionText, String name, byte[] bytecode) { - name = name.replace('.', '/'); - String dir = ""; - if (name.indexOf('/') != -1) { - dir = name.substring(0, name.lastIndexOf('/')); - } - String dumplocation = null; + String nameToUse = name.replace('.', '/'); + String dir = (nameToUse.indexOf('/') != -1 ? nameToUse.substring(0, nameToUse.lastIndexOf('/')) : ""); + String dumpLocation = null; try { - File tempfile = null; - tempfile = File.createTempFile("tmp", null); - tempfile.delete(); - File f = new File(tempfile, dir); + File tempFile = File.createTempFile("tmp", null); + dumpLocation = tempFile + File.separator + nameToUse + ".class"; + tempFile.delete(); + File f = new File(tempFile, dir); f.mkdirs(); - dumplocation = tempfile + File.separator + name + ".class"; - System.out.println("Expression '" + expressionText + "' compiled code dumped to " - + dumplocation); - f = new File(dumplocation); + if (logger.isDebugEnabled()) { + logger.debug("Expression '" + expressionText + "' compiled code dumped to " + dumpLocation); + } + f = new File(dumpLocation); FileOutputStream fos = new FileOutputStream(f); fos.write(bytecode); fos.flush(); fos.close(); } - catch (IOException ioe) { - throw new IllegalStateException("Unexpected problem dumping class " - + name + " into " + dumplocation, ioe); + catch (IOException ex) { + throw new IllegalStateException("Unexpected problem dumping class " + nameToUse + " into " + dumpLocation, ex); } } @@ -246,32 +256,6 @@ public class SpelCompiler implements Opcodes { public Class defineClass(String name, byte[] bytes) { return super.defineClass(name, bytes, 0, bytes.length); } - } - /** - * 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 - */ - public static boolean compile(Expression expression) { - if (expression instanceof SpelExpression) { - SpelExpression spelExpression = (SpelExpression)expression; - return spelExpression.compileExpression(); - } - return false; - } - - /** - * Request to revert to the interpreter for expression evaluation. Any compiled form - * is discarded but can be recreated by later recompiling again. - * @param expression the expression - */ - public static void revertToInterpreted(Expression expression) { - if (expression instanceof SpelExpression) { - SpelExpression spelExpression = (SpelExpression)expression; - spelExpression.revertToInterpreted(); - } - } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java index 7d04a14b310..9c5012902bf 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java @@ -44,25 +44,32 @@ import org.springframework.util.Assert; */ public class SpelExpression implements Expression { + // Number of times to interpret an expression before compiling it + private static final int INTERPRETED_COUNT_THRESHOLD = 100; + + // Number of times to try compiling an expression before giving up + private static final int FAILED_ATTEMPTS_THRESHOLD = 100; + + private final String expression; - // Holds the compiled form of the expression (if it has been compiled) - private CompiledExpression compiledAst; - - private SpelNodeImpl ast; + private final SpelNodeImpl ast; private final SpelParserConfiguration configuration; // the default context is used if no override is supplied by the user - private EvaluationContext defaultContext; + private EvaluationContext evaluationContext; + + // Holds the compiled form of the expression (if it has been compiled) + private CompiledExpression compiledAst; // Count of many times as the expression been interpreted - can trigger compilation // when certain limit reached - private int interpretedCount = 0; + private volatile int interpretedCount = 0; // The number of times compilation was attempted and failed - enables us to eventually // give up trying to compile it when it just doesn't seem to be possible. - private int failedAttempts = 0; + private volatile int failedAttempts = 0; /** @@ -75,23 +82,44 @@ public class SpelExpression implements Expression { } + /** + * Set the evaluation context that will be used if none is specified on an evaluation call. + * @param evaluationContext the evaluation context to use + */ + public void setEvaluationContext(EvaluationContext evaluationContext) { + this.evaluationContext = evaluationContext; + } + + /** + * Return the default evaluation context that will be used if none is supplied on an evaluation call. + * @return the default evaluation context + */ + public EvaluationContext getEvaluationContext() { + if (this.evaluationContext == null) { + this.evaluationContext = new StandardEvaluationContext(); + } + return this.evaluationContext; + } + + // implementing Expression @Override public Object getValue() throws EvaluationException { - Object result = null; - if (compiledAst != null) { + Object result; + if (this.compiledAst != null) { try { return this.compiledAst.getValue(null,null); - } catch (Throwable t) { + } + catch (Throwable ex) { // If running in mixed mode, revert to interpreted - if (this.configuration.getCompilerMode() == SpelCompilerMode.mixed) { - interpretedCount = 0; - compiledAst = null; + if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) { + this.interpretedCount = 0; + this.compiledAst = null; } else { // Running in SpelCompilerMode.immediate mode - propagate exception to caller - throw new SpelEvaluationException(t,SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); + throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); } } } @@ -103,19 +131,20 @@ public class SpelExpression implements Expression { @Override public Object getValue(Object rootObject) throws EvaluationException { - Object result = null; - if (compiledAst!=null) { + Object result; + if (this.compiledAst != null) { try { return this.compiledAst.getValue(rootObject,null); - } catch (Throwable t) { + } + catch (Throwable ex) { // If running in mixed mode, revert to interpreted - if (this.configuration.getCompilerMode() == SpelCompilerMode.mixed) { - interpretedCount = 0; - compiledAst = null; + if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) { + this.interpretedCount = 0; + this.compiledAst = null; } else { // Running in SpelCompilerMode.immediate mode - propagate exception to caller - throw new SpelEvaluationException(t,SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); + throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); } } } @@ -128,23 +157,25 @@ public class SpelExpression implements Expression { @SuppressWarnings("unchecked") @Override public T getValue(Class expectedResultType) throws EvaluationException { - if (compiledAst!=null) { + if (this.compiledAst != null) { try { Object result = this.compiledAst.getValue(null,null); if (expectedResultType == null) { return (T)result; - } else { + } + else { return ExpressionUtils.convertTypedValue(getEvaluationContext(), new TypedValue(result), expectedResultType); } - } catch (Throwable t) { + } + catch (Throwable ex) { // If running in mixed mode, revert to interpreted - if (this.configuration.getCompilerMode() == SpelCompilerMode.mixed) { - interpretedCount = 0; - compiledAst = null; + if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) { + this.interpretedCount = 0; + this.compiledAst = null; } else { // Running in SpelCompilerMode.immediate mode - propagate exception to caller - throw new SpelEvaluationException(t,SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); + throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); } } } @@ -157,23 +188,25 @@ public class SpelExpression implements Expression { @SuppressWarnings("unchecked") @Override public T getValue(Object rootObject, Class expectedResultType) throws EvaluationException { - if (compiledAst!=null) { + if (this.compiledAst != null) { try { - Object result = this.compiledAst.getValue(rootObject,null); + Object result = this.compiledAst.getValue(rootObject, null); if (expectedResultType == null) { return (T)result; - } else { + } + else { return ExpressionUtils.convertTypedValue(getEvaluationContext(), new TypedValue(result), expectedResultType); } - } catch (Throwable t) { + } + catch (Throwable ex) { // If running in mixed mode, revert to interpreted - if (this.configuration.getCompilerMode() == SpelCompilerMode.mixed) { - interpretedCount = 0; - compiledAst = null; + if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) { + this.interpretedCount = 0; + this.compiledAst = null; } else { // Running in SpelCompilerMode.immediate mode - propagate exception to caller - throw new SpelEvaluationException(t,SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); + throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); } } } @@ -190,15 +223,16 @@ public class SpelExpression implements Expression { try { Object result = this.compiledAst.getValue(null,context); return result; - } catch (Throwable t) { + } + catch (Throwable ex) { // If running in mixed mode, revert to interpreted - if (this.configuration.getCompilerMode() == SpelCompilerMode.mixed) { - interpretedCount = 0; - compiledAst = null; + if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) { + this.interpretedCount = 0; + this.compiledAst = null; } else { // Running in SpelCompilerMode.immediate mode - propagate exception to caller - throw new SpelEvaluationException(t,SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); + throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); } } } @@ -211,18 +245,19 @@ public class SpelExpression implements Expression { @Override public Object getValue(EvaluationContext context, Object rootObject) throws EvaluationException { Assert.notNull(context, "The EvaluationContext is required"); - if (compiledAst!=null) { + if (this.compiledAst != null) { try { return this.compiledAst.getValue(rootObject,context); - } catch (Throwable t) { + } + catch (Throwable ex) { // If running in mixed mode, revert to interpreted - if (this.configuration.getCompilerMode() == SpelCompilerMode.mixed) { - interpretedCount = 0; - compiledAst = null; + if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) { + this.interpretedCount = 0; + this.compiledAst = null; } else { // Running in SpelCompilerMode.immediate mode - propagate exception to caller - throw new SpelEvaluationException(t,SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); + throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); } } } @@ -235,23 +270,25 @@ public class SpelExpression implements Expression { @SuppressWarnings("unchecked") @Override public T getValue(EvaluationContext context, Class expectedResultType) throws EvaluationException { - if (compiledAst!=null) { + if (this.compiledAst != null) { try { Object result = this.compiledAst.getValue(null,context); - if (expectedResultType!=null) { - return (T) result; - } else { + if (expectedResultType != null) { return ExpressionUtils.convertTypedValue(context, new TypedValue(result), expectedResultType); } - } catch (Throwable t) { + else { + return (T) result; + } + } + catch (Throwable ex) { // If running in mixed mode, revert to interpreted - if (this.configuration.getCompilerMode() == SpelCompilerMode.mixed) { - interpretedCount = 0; - compiledAst = null; + if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) { + this.interpretedCount = 0; + this.compiledAst = null; } else { // Running in SpelCompilerMode.immediate mode - propagate exception to caller - throw new SpelEvaluationException(t,SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); + throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); } } } @@ -264,23 +301,25 @@ public class SpelExpression implements Expression { @SuppressWarnings("unchecked") @Override public T getValue(EvaluationContext context, Object rootObject, Class expectedResultType) throws EvaluationException { - if (compiledAst!=null) { + if (this.compiledAst != null) { try { Object result = this.compiledAst.getValue(rootObject,context); - if (expectedResultType!=null) { - return (T) result; - } else { + if (expectedResultType != null) { return ExpressionUtils.convertTypedValue(context, new TypedValue(result), expectedResultType); } - } catch (Throwable t) { + else { + return (T) result; + } + } + catch (Throwable ex) { // If running in mixed mode, revert to interpreted - if (this.configuration.getCompilerMode() == SpelCompilerMode.mixed) { - interpretedCount = 0; - compiledAst = null; + if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) { + this.interpretedCount = 0; + this.compiledAst = null; } else { // Running in SpelCompilerMode.immediate mode - propagate exception to caller - throw new SpelEvaluationException(t,SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); + throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); } } } @@ -305,14 +344,14 @@ public class SpelExpression implements Expression { Assert.notNull(context, "The EvaluationContext is required"); ExpressionState eState = new ExpressionState(context, this.configuration); TypeDescriptor typeDescriptor = this.ast.getValueInternal(eState).getTypeDescriptor(); - return typeDescriptor != null ? typeDescriptor.getType() : null; + return (typeDescriptor != null ? typeDescriptor.getType() : null); } @Override public Class getValueType(EvaluationContext context, Object rootObject) throws EvaluationException { ExpressionState eState = new ExpressionState(context, toTypedValue(rootObject), this.configuration); TypeDescriptor typeDescriptor = this.ast.getValueInternal(eState).getTypeDescriptor(); - return typeDescriptor != null ? typeDescriptor.getType() : null; + return (typeDescriptor != null ? typeDescriptor.getType() : null); } @Override @@ -379,6 +418,7 @@ public class SpelExpression implements Expression { this.ast.setValue(new ExpressionState(context, toTypedValue(rootObject), this.configuration), value); } + // impl only /** @@ -386,17 +426,17 @@ public class SpelExpression implements Expression { * @param expressionState the expression state used to determine compilation mode */ private void checkCompile(ExpressionState expressionState) { - interpretedCount++; + this.interpretedCount++; SpelCompilerMode compilerMode = expressionState.getConfiguration().getCompilerMode(); - if (compilerMode != SpelCompilerMode.off) { - if (compilerMode == SpelCompilerMode.immediate) { - if (interpretedCount > 1) { + if (compilerMode != SpelCompilerMode.OFF) { + if (compilerMode == SpelCompilerMode.IMMEDIATE) { + if (this.interpretedCount > 1) { compileExpression(); } } else { - // compilerMode = SpelCompilerMode.mixed - if (interpretedCount > SpelCompiler.interpretedCountThreshold) { + // compilerMode = SpelCompilerMode.MIXED + if (this.interpretedCount > INTERPRETED_COUNT_THRESHOLD) { compileExpression(); } } @@ -410,20 +450,20 @@ public class SpelExpression implements Expression { * no longer considered suitable for compilation. */ public boolean compileExpression() { - if (failedAttempts > 100) { + if (this.failedAttempts > FAILED_ATTEMPTS_THRESHOLD) { // Don't try again return false; } if (this.compiledAst == null) { - synchronized (expression) { - // Possibly compiled by another thread before this thread got into the - // sync block + synchronized (this.expression) { + // Possibly compiled by another thread before this thread got into the sync block if (this.compiledAst != null) { return true; } - this.compiledAst = SpelCompiler.getCompiler().compile(this.ast); + SpelCompiler compiler = SpelCompiler.getCompiler(this.configuration.getCompilerClassLoader()); + this.compiledAst = compiler.compile(this.ast); if (this.compiledAst == null) { - failedAttempts++; + this.failedAttempts++; } } } @@ -458,25 +498,6 @@ public class SpelExpression implements Expression { return this.ast.toStringAST(); } - /** - * Return the default evaluation context that will be used if none is supplied on an evaluation call - * @return the default evaluation context - */ - public EvaluationContext getEvaluationContext() { - if (this.defaultContext == null) { - this.defaultContext = new StandardEvaluationContext(); - } - return this.defaultContext; - } - - /** - * Set the evaluation context that will be used if none is specified on an evaluation call. - * @param context an evaluation context - */ - public void setEvaluationContext(EvaluationContext context) { - this.defaultContext = context; - } - private TypedValue toTypedValue(Object object) { if (object == null) { return TypedValue.NULL; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java index 4f69baebcad..e3eb61a9b3e 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -35,14 +35,14 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { /** - * Create a parser with standard configuration. + * Create a parser with default settings. */ public SpelExpressionParser() { - this.configuration = new SpelParserConfiguration(false, false); + this.configuration = new SpelParserConfiguration(); } /** - * Create a parser with some configured behavior. + * Create a parser with the specified configuration. * @param configuration custom configuration options */ public SpelExpressionParser(SpelParserConfiguration configuration) { @@ -51,13 +51,13 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { } + public SpelExpression parseRaw(String expressionString) throws ParseException { + return doParseExpression(expressionString, null); + } + @Override protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException { return new InternalSpelExpressionParser(this.configuration).doParseExpression(expressionString, context); } - public SpelExpression parseRaw(String expressionString) throws ParseException { - return doParseExpression(expressionString, null); - } - } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java index 32d06fb40a7..c81af080797 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java @@ -35,13 +35,12 @@ import org.springframework.core.convert.Property; import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.style.ToStringCreator; import org.springframework.expression.AccessException; -import org.springframework.expression.CompilablePropertyAccessor; import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationException; import org.springframework.expression.PropertyAccessor; import org.springframework.expression.TypedValue; -import org.springframework.expression.spel.ast.PropertyOrFieldReference; -import org.springframework.expression.spel.standard.CodeFlow; +import org.springframework.expression.spel.CodeFlow; +import org.springframework.expression.spel.CompilablePropertyAccessor; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; @@ -370,10 +369,10 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { Method[] methods = getSortedClassMethods(clazz); for (String methodSuffix : methodSuffixes) { for (Method method : methods) { - if (method.getName().equals(prefix + methodSuffix) - && method.getParameterTypes().length == numberOfParams - && (!mustBeStatic || Modifier.isStatic(method.getModifiers())) - && (requiredReturnTypes.isEmpty() || requiredReturnTypes.contains(method.getReturnType()))) { + if (method.getName().equals(prefix + methodSuffix) && + method.getParameterTypes().length == numberOfParams && + (!mustBeStatic || Modifier.isStatic(method.getModifiers())) && + (requiredReturnTypes.isEmpty() || requiredReturnTypes.contains(method.getReturnType()))) { return method; } } @@ -649,16 +648,6 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { } throw new AccessException("Neither getter nor field found for property '" + name + "'"); } - - @Override - public Class getPropertyType() { - if (member instanceof Field) { - return ((Field)member).getType(); - } - else { - return ((Method)member).getReturnType(); - } - } @Override public boolean canWrite(EvaluationContext context, Object target, String name) { @@ -678,11 +667,20 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { } return true; } - - @Override - public void generateCode(PropertyOrFieldReference propertyReference, MethodVisitor mv,CodeFlow codeflow) { - boolean isStatic = Modifier.isStatic(member.getModifiers()); + @Override + public Class getPropertyType() { + if (member instanceof Field) { + return ((Field) member).getType(); + } + else { + return ((Method) member).getReturnType(); + } + } + + @Override + public void generateCode(String propertyName, MethodVisitor mv, CodeFlow codeflow) { + boolean isStatic = Modifier.isStatic(member.getModifiers()); String descriptor = codeflow.lastDescriptor(); String memberDeclaringClassSlashedDescriptor = member.getDeclaringClass().getName().replace('.','/'); if (!isStatic) { @@ -694,9 +692,12 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { } } if (member instanceof Field) { - mv.visitFieldInsn(isStatic?GETSTATIC:GETFIELD,memberDeclaringClassSlashedDescriptor,member.getName(),CodeFlow.toJVMDescriptor(((Field) member).getType())); - } else { - mv.visitMethodInsn(isStatic?INVOKESTATIC:INVOKEVIRTUAL, memberDeclaringClassSlashedDescriptor, member.getName(),CodeFlow.createSignatureDescriptor((Method)member),false); + mv.visitFieldInsn(isStatic ? GETSTATIC : GETFIELD, memberDeclaringClassSlashedDescriptor, + member.getName(), CodeFlow.toJVMDescriptor(((Field) member).getType())); + } + else { + mv.visitMethodInsn(isStatic ? INVOKESTATIC : INVOKEVIRTUAL, memberDeclaringClassSlashedDescriptor, + member.getName(), CodeFlow.createSignatureDescriptor((Method) member),false); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardEvaluationContext.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardEvaluationContext.java index 7f02343b396..5efc4456160 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardEvaluationContext.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardEvaluationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -54,6 +54,8 @@ public class StandardEvaluationContext implements EvaluationContext { private List methodResolvers; + private BeanResolver beanResolver; + private ReflectiveMethodResolver reflectiveMethodResolver; private List propertyAccessors; @@ -68,15 +70,12 @@ public class StandardEvaluationContext implements EvaluationContext { private final Map variables = new HashMap(); - private BeanResolver beanResolver; - public StandardEvaluationContext() { setRootObject(null); } public StandardEvaluationContext(Object rootObject) { - this(); setRootObject(rootObject); } diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java index 19e27f46c4e..4e380e24bc2 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java @@ -25,18 +25,16 @@ import java.util.Map; import java.util.StringTokenizer; import org.junit.Test; + import org.springframework.asm.MethodVisitor; import org.springframework.expression.AccessException; -import org.springframework.expression.CompilablePropertyAccessor; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.TypedValue; import org.springframework.expression.spel.ast.CompoundExpression; import org.springframework.expression.spel.ast.OpLT; -import org.springframework.expression.spel.ast.PropertyOrFieldReference; import org.springframework.expression.spel.ast.SpelNodeImpl; import org.springframework.expression.spel.ast.Ternary; -import org.springframework.expression.spel.standard.CodeFlow; import org.springframework.expression.spel.standard.SpelCompiler; import org.springframework.expression.spel.standard.SpelExpression; import org.springframework.expression.spel.support.StandardEvaluationContext; @@ -2174,63 +2172,7 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { vc = expression.getValue(payload); assertNull(vc); } - - static class MyAccessor implements CompilablePropertyAccessor { - - private Method method; - - public Class[] getSpecificTargetClasses() { - return new Class[]{Payload2.class}; - } - public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { - // target is a Payload2 instance - return true; - } - - public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { - Payload2 payload2 = (Payload2)target; - return new TypedValue(payload2.getField(name)); - } - - public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { - return false; - } - - public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { - } - - @Override - public boolean isCompilable() { - return true; - } - - @Override - public void generateCode(PropertyOrFieldReference propertyReference, MethodVisitor mv,CodeFlow codeflow) { - if (method == null) { - try { - method = Payload2.class.getDeclaredMethod("getField", String.class); - } catch (Exception e) {} - } - String descriptor = codeflow.lastDescriptor(); - String memberDeclaringClassSlashedDescriptor = method.getDeclaringClass().getName().replace('.','/'); - if (descriptor == null) { - codeflow.loadTarget(mv); - } - if (descriptor == null || !memberDeclaringClassSlashedDescriptor.equals(descriptor.substring(1))) { - mv.visitTypeInsn(CHECKCAST, memberDeclaringClassSlashedDescriptor); - } - mv.visitLdcInsn(propertyReference.getName()); - mv.visitMethodInsn(INVOKEVIRTUAL, memberDeclaringClassSlashedDescriptor, method.getName(),CodeFlow.createSignatureDescriptor(method),false); - } - - @Override - public Class getPropertyType() { - return Object.class; - } - - } - @Test public void variantGetter() throws Exception { Payload2Holder holder = new Payload2Holder(); @@ -2257,9 +2199,67 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { // v = expression.getValue(ctx,holder); // } // System.out.println((System.currentTimeMillis()-stime)); - } - + + + static class MyAccessor implements CompilablePropertyAccessor { + + private Method method; + + public Class[] getSpecificTargetClasses() { + return new Class[]{Payload2.class}; + } + + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + // target is a Payload2 instance + return true; + } + + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + Payload2 payload2 = (Payload2)target; + return new TypedValue(payload2.getField(name)); + } + + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + return false; + } + + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + } + + @Override + public boolean isCompilable() { + return true; + } + + @Override + public Class getPropertyType() { + return Object.class; + } + + @Override + public void generateCode(String propertyName, MethodVisitor mv,CodeFlow codeflow) { + if (method == null) { + try { + method = Payload2.class.getDeclaredMethod("getField", String.class); + } + catch (Exception e) { + } + } + String descriptor = codeflow.lastDescriptor(); + String memberDeclaringClassSlashedDescriptor = method.getDeclaringClass().getName().replace('.','/'); + if (descriptor == null) { + codeflow.loadTarget(mv); + } + if (descriptor == null || !memberDeclaringClassSlashedDescriptor.equals(descriptor.substring(1))) { + mv.visitTypeInsn(CHECKCAST, memberDeclaringClassSlashedDescriptor); + } + mv.visitLdcInsn(propertyName); + mv.visitMethodInsn(INVOKEVIRTUAL, memberDeclaringClassSlashedDescriptor, method.getName(),CodeFlow.createSignatureDescriptor(method),false); + } + } + + static class CompilableMapAccessor implements CompilablePropertyAccessor { @Override @@ -2295,40 +2295,23 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { return new Class[] {Map.class}; } - - /** - * Exception thrown from {@code read} in order to reset a cached - * PropertyAccessor, allowing other accessors to have a try. - */ - @SuppressWarnings("serial") - private static class MapAccessException extends AccessException { - - private final String key; - - public MapAccessException(String key) { - super(null); - this.key = key; - } - - @Override - public String getMessage() { - return "Map does not contain a value for key '" + this.key + "'"; - } - } - @Override public boolean isCompilable() { return true; } - + @Override - public void generateCode(PropertyOrFieldReference propertyReference, - MethodVisitor mv, CodeFlow codeflow) { + public Class getPropertyType() { + return Object.class; + } + + @Override + public void generateCode(String propertyName, MethodVisitor mv, CodeFlow codeflow) { String descriptor = codeflow.lastDescriptor(); if (descriptor == null) { codeflow.loadTarget(mv); } - mv.visitLdcInsn(propertyReference.getName()); + mv.visitLdcInsn(propertyName); mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get","(Ljava/lang/Object;)Ljava/lang/Object;",true); // if (method == null) { @@ -2348,12 +2331,27 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { // mv.visitMethodInsn(INVOKEVIRTUAL, memberDeclaringClassSlashedDescriptor, method.getName(),CodeFlow.createDescriptor(method)); // 6: invokeinterface #6, 2; //InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object; } + } - @Override - public Class getPropertyType() { - return Object.class; + + /** + * Exception thrown from {@code read} in order to reset a cached + * PropertyAccessor, allowing other accessors to have a try. + */ + @SuppressWarnings("serial") + private static class MapAccessException extends AccessException { + + private final String key; + + public MapAccessException(String key) { + super(null); + this.key = key; } + @Override + public String getMessage() { + return "Map does not contain a value for key '" + this.key + "'"; + } }