Backport selected refinements from the nullability efforts
Issue: SPR-15656
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -25,6 +25,14 @@ package org.springframework.expression;
|
||||
@SuppressWarnings("serial")
|
||||
public class AccessException extends Exception {
|
||||
|
||||
/**
|
||||
* Create an AccessException with a specific message.
|
||||
* @param message the message
|
||||
*/
|
||||
public AccessException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an AccessException with a specific message and cause.
|
||||
* @param message the message
|
||||
@@ -34,12 +42,4 @@ public class AccessException extends Exception {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an AccessException with a specific message.
|
||||
* @param message the message
|
||||
*/
|
||||
public AccessException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,13 +36,12 @@ public interface ConstructorExecutor {
|
||||
|
||||
/**
|
||||
* Execute a constructor in the specified context using the specified arguments.
|
||||
*
|
||||
* @param context the evaluation context in which the command is being executed
|
||||
* @param arguments the arguments to the constructor call, should match (in terms of
|
||||
* number and type) whatever the command will need to run
|
||||
* @param arguments the arguments to the constructor call, should match (in terms
|
||||
* of number and type) whatever the command will need to run
|
||||
* @return the new object
|
||||
* @throws AccessException if there is a problem executing the command or the
|
||||
* CommandExecutor is no longer valid
|
||||
* CommandExecutor is no longer valid
|
||||
*/
|
||||
TypedValue execute(EvaluationContext context, Object... arguments) throws AccessException;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -17,9 +17,9 @@
|
||||
package org.springframework.expression;
|
||||
|
||||
/**
|
||||
* By default the mathematical operators {@link Operation} support simple types like
|
||||
* numbers. By providing an implementation of OperatorOverloader, a user of the expression
|
||||
* language can support these operations on other types.
|
||||
* By default the mathematical operators {@link Operation} support simple types
|
||||
* like numbers. By providing an implementation of OperatorOverloader, a user
|
||||
* of the expression language can support these operations on other types.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
@@ -27,21 +27,21 @@ package org.springframework.expression;
|
||||
public interface OperatorOverloader {
|
||||
|
||||
/**
|
||||
* Return true if the operator overloader supports the specified operation between the
|
||||
* two operands and so should be invoked to handle it.
|
||||
* Return true if the operator overloader supports the specified operation
|
||||
* between the two operands and so should be invoked to handle it.
|
||||
* @param operation the operation to be performed
|
||||
* @param leftOperand the left operand
|
||||
* @param rightOperand the right operand
|
||||
* @return true if the OperatorOverloader supports the specified operation between the
|
||||
* two operands
|
||||
* @return true if the OperatorOverloader supports the specified operation
|
||||
* between the two operands
|
||||
* @throws EvaluationException if there is a problem performing the operation
|
||||
*/
|
||||
boolean overridesOperation(Operation operation, Object leftOperand, Object rightOperand)
|
||||
throws EvaluationException;
|
||||
|
||||
/**
|
||||
* Execute the specified operation on two operands, returning a result. See
|
||||
* {@link Operation} for supported operations.
|
||||
* Execute the specified operation on two operands, returning a result.
|
||||
* See {@link Operation} for supported operations.
|
||||
* @param operation the operation to be performed
|
||||
* @param leftOperand the left operand
|
||||
* @param rightOperand the right operand
|
||||
|
||||
@@ -112,6 +112,7 @@ public abstract class TemplateAwareExpressionParser implements ExpressionParser
|
||||
String prefix = context.getExpressionPrefix();
|
||||
String suffix = context.getExpressionSuffix();
|
||||
int startIdx = 0;
|
||||
|
||||
while (startIdx < expressionString.length()) {
|
||||
int prefixIndex = expressionString.indexOf(prefix, startIdx);
|
||||
if (prefixIndex >= startIdx) {
|
||||
@@ -126,22 +127,18 @@ public abstract class TemplateAwareExpressionParser implements ExpressionParser
|
||||
"No ending suffix '" + suffix + "' for expression starting at character " +
|
||||
prefixIndex + ": " + expressionString.substring(prefixIndex));
|
||||
}
|
||||
|
||||
if (suffixIndex == afterPrefixIndex) {
|
||||
throw new ParseException(expressionString, prefixIndex,
|
||||
"No expression defined within delimiter '" + prefix + suffix +
|
||||
"' at character " + prefixIndex);
|
||||
}
|
||||
|
||||
String expr = expressionString.substring(prefixIndex + prefix.length(), suffixIndex);
|
||||
expr = expr.trim();
|
||||
|
||||
if (expr.isEmpty()) {
|
||||
throw new ParseException(expressionString, prefixIndex,
|
||||
"No expression defined within delimiter '" + prefix + suffix +
|
||||
"' at character " + prefixIndex);
|
||||
}
|
||||
|
||||
expressions.add(doParseExpression(expr, context));
|
||||
startIdx = suffixIndex + suffix.length();
|
||||
}
|
||||
@@ -151,6 +148,7 @@ public abstract class TemplateAwareExpressionParser implements ExpressionParser
|
||||
startIdx = expressionString.length();
|
||||
}
|
||||
}
|
||||
|
||||
return expressions.toArray(new Expression[expressions.size()]);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -32,6 +32,7 @@ import org.springframework.expression.TypeComparator;
|
||||
import org.springframework.expression.TypeConverter;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* An ExpressionState is for maintaining per-expression-evaluation state, any changes to
|
||||
@@ -53,6 +54,12 @@ public class ExpressionState {
|
||||
|
||||
private final TypedValue rootObject;
|
||||
|
||||
private final SpelParserConfiguration configuration;
|
||||
|
||||
private Stack<TypedValue> contextObjects;
|
||||
|
||||
private Stack<VariableScope> variableScopes;
|
||||
|
||||
// When entering a new scope there is a new base object which should be used
|
||||
// for '#this' references (or to act as a target for unqualified references).
|
||||
// This stack captures those objects at each nested scope level.
|
||||
@@ -62,12 +69,6 @@ public class ExpressionState {
|
||||
// element from list1
|
||||
private Stack<TypedValue> scopeRootObjects;
|
||||
|
||||
private final SpelParserConfiguration configuration;
|
||||
|
||||
private Stack<VariableScope> variableScopes;
|
||||
|
||||
private Stack<TypedValue> contextObjects;
|
||||
|
||||
|
||||
public ExpressionState(EvaluationContext context) {
|
||||
this(context, context.getRootObject(), new SpelParserConfiguration(false, false));
|
||||
@@ -105,7 +106,7 @@ public class ExpressionState {
|
||||
* The active context object is what unqualified references to properties/etc are resolved against.
|
||||
*/
|
||||
public TypedValue getActiveContextObject() {
|
||||
if (this.contextObjects == null || this.contextObjects.isEmpty()) {
|
||||
if (CollectionUtils.isEmpty(this.contextObjects)) {
|
||||
return this.rootObject;
|
||||
}
|
||||
return this.contextObjects.peek();
|
||||
@@ -130,7 +131,7 @@ public class ExpressionState {
|
||||
}
|
||||
|
||||
public TypedValue getScopeRootContextObject() {
|
||||
if (this.scopeRootObjects == null || this.scopeRootObjects.isEmpty()) {
|
||||
if (CollectionUtils.isEmpty(this.scopeRootObjects)) {
|
||||
return this.rootObject;
|
||||
}
|
||||
return this.scopeRootObjects.peek();
|
||||
@@ -142,12 +143,7 @@ public class ExpressionState {
|
||||
|
||||
public TypedValue lookupVariable(String name) {
|
||||
Object value = this.relatedContext.lookupVariable(name);
|
||||
if (value == null) {
|
||||
return TypedValue.NULL;
|
||||
}
|
||||
else {
|
||||
return new TypedValue(value);
|
||||
}
|
||||
return (value != null ? new TypedValue(value) : TypedValue.NULL);
|
||||
}
|
||||
|
||||
public TypeComparator getTypeComparator() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -18,7 +18,6 @@ package org.springframework.expression.spel;
|
||||
|
||||
import org.springframework.core.SpringProperties;
|
||||
|
||||
|
||||
/**
|
||||
* Configuration object for the SpEL expression parser.
|
||||
*
|
||||
@@ -106,35 +105,35 @@ public class SpelParserConfiguration {
|
||||
|
||||
|
||||
/**
|
||||
* @return the configuration mode for parsers using this configuration object
|
||||
* Return the configuration mode for parsers using this configuration object.
|
||||
*/
|
||||
public SpelCompilerMode getCompilerMode() {
|
||||
return this.compilerMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ClassLoader to use as the basis for expression compilation
|
||||
* 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
|
||||
* Return {@code true} if {@code null} references should be automatically grown.
|
||||
*/
|
||||
public boolean isAutoGrowNullReferences() {
|
||||
return this.autoGrowNullReferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if collections should be automatically grown
|
||||
* Return {@code true} if collections should be automatically grown.
|
||||
*/
|
||||
public boolean isAutoGrowCollections() {
|
||||
return this.autoGrowCollections;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the maximum size that a collection can auto grow
|
||||
* Return the maximum size that a collection can auto grow.
|
||||
*/
|
||||
public int getMaximumAutoGrowSize() {
|
||||
return this.maximumAutoGrowSize;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -37,7 +37,7 @@ public class BeanReference extends SpelNodeImpl {
|
||||
private final String beanName;
|
||||
|
||||
|
||||
public BeanReference(int pos,String beanName) {
|
||||
public BeanReference(int pos, String beanName) {
|
||||
super(pos);
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -31,7 +31,7 @@ import org.springframework.expression.spel.SpelEvaluationException;
|
||||
*/
|
||||
public class CompoundExpression extends SpelNodeImpl {
|
||||
|
||||
public CompoundExpression(int pos,SpelNodeImpl... expressionComponents) {
|
||||
public CompoundExpression(int pos, SpelNodeImpl... expressionComponents) {
|
||||
super(pos, expressionComponents);
|
||||
if (expressionComponents.length < 2) {
|
||||
throw new IllegalStateException("Do not build compound expressions with less than two entries: " +
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -59,7 +59,7 @@ public class FunctionReference extends SpelNodeImpl {
|
||||
|
||||
|
||||
public FunctionReference(String functionName, int pos, SpelNodeImpl... arguments) {
|
||||
super(pos,arguments);
|
||||
super(pos, arguments);
|
||||
this.name = functionName;
|
||||
}
|
||||
|
||||
@@ -107,15 +107,15 @@ public class FunctionReference extends SpelNodeImpl {
|
||||
SpelMessage.FUNCTION_MUST_BE_STATIC, ClassUtils.getQualifiedMethodName(method), this.name);
|
||||
}
|
||||
|
||||
argumentConversionOccurred = false;
|
||||
this.argumentConversionOccurred = false;
|
||||
// Convert arguments if necessary and remap them for varargs if required
|
||||
if (functionArgs != null) {
|
||||
TypeConverter converter = state.getEvaluationContext().getTypeConverter();
|
||||
argumentConversionOccurred = ReflectionHelper.convertAllArguments(converter, functionArgs, method);
|
||||
this.argumentConversionOccurred = ReflectionHelper.convertAllArguments(converter, functionArgs, method);
|
||||
}
|
||||
if (method.isVarArgs()) {
|
||||
functionArgs =
|
||||
ReflectionHelper.setupArgumentsForVarargsInvocation(method.getParameterTypes(), functionArgs);
|
||||
functionArgs = ReflectionHelper.setupArgumentsForVarargsInvocation(
|
||||
method.getParameterTypes(), functionArgs);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -51,7 +51,7 @@ import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
|
||||
// TODO support correct syntax for multidimensional [][][] and not [,,,]
|
||||
public class Indexer extends SpelNodeImpl {
|
||||
|
||||
private static enum IndexedType {ARRAY, LIST, MAP, STRING, OBJECT}
|
||||
private enum IndexedType {ARRAY, LIST, MAP, STRING, OBJECT}
|
||||
|
||||
|
||||
// These fields are used when the indexer is being used as a property read accessor.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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,7 @@ import org.springframework.expression.spel.CodeFlow;
|
||||
public class NullLiteral extends Literal {
|
||||
|
||||
public NullLiteral(int pos) {
|
||||
super(null,pos);
|
||||
super(null, pos);
|
||||
this.exitTypeDescriptor = "Ljava/lang/Object";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -44,7 +44,7 @@ public class OpAnd extends Operator {
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
if (getBooleanValue(state, getLeftOperand()) == false) {
|
||||
if (!getBooleanValue(state, getLeftOperand())) {
|
||||
// no need to evaluate right operand
|
||||
return BooleanTypedValue.FALSE;
|
||||
}
|
||||
|
||||
@@ -192,8 +192,8 @@ public class OpPlus extends Operator {
|
||||
private void walk(MethodVisitor mv, CodeFlow cf, SpelNodeImpl operand) {
|
||||
if (operand instanceof OpPlus) {
|
||||
OpPlus plus = (OpPlus)operand;
|
||||
walk(mv,cf,plus.getLeftOperand());
|
||||
walk(mv,cf,plus.getRightOperand());
|
||||
walk(mv, cf, plus.getLeftOperand());
|
||||
walk(mv, cf, plus.getRightOperand());
|
||||
}
|
||||
else {
|
||||
cf.enterCompilationScope();
|
||||
|
||||
@@ -87,7 +87,7 @@ public abstract class Operator extends SpelNodeImpl {
|
||||
|
||||
protected boolean isCompilableOperatorUsingNumerics() {
|
||||
SpelNodeImpl left = getLeftOperand();
|
||||
SpelNodeImpl right= getRightOperand();
|
||||
SpelNodeImpl right = getRightOperand();
|
||||
if (!left.isCompilable() || !right.isCompilable()) {
|
||||
return false;
|
||||
}
|
||||
@@ -273,11 +273,11 @@ public abstract class Operator extends SpelNodeImpl {
|
||||
boolean rightNumeric = CodeFlow.isPrimitiveOrUnboxableSupportedNumberOrBoolean(rd);
|
||||
|
||||
// If the declared descriptors aren't providing the information, try the actual descriptors
|
||||
if (!leftNumeric && !ld.equals(leftActualDescriptor)) {
|
||||
if (!leftNumeric && !ObjectUtils.nullSafeEquals(ld, leftActualDescriptor)) {
|
||||
ld = leftActualDescriptor;
|
||||
leftNumeric = CodeFlow.isPrimitiveOrUnboxableSupportedNumberOrBoolean(ld);
|
||||
}
|
||||
if (!rightNumeric && !rd.equals(rightActualDescriptor)) {
|
||||
if (!rightNumeric && !ObjectUtils.nullSafeEquals(rd, rightActualDescriptor)) {
|
||||
rd = rightActualDescriptor;
|
||||
rightNumeric = CodeFlow.isPrimitiveOrUnboxableSupportedNumberOrBoolean(rd);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -77,6 +77,7 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
protected SpelNodeImpl getPreviousChild() {
|
||||
SpelNodeImpl result = null;
|
||||
if (this.parent != null) {
|
||||
@@ -214,9 +215,9 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
|
||||
|
||||
|
||||
/**
|
||||
* Generate code that handles building the argument values for the specified method. This method will take account
|
||||
* of whether the invoked method is a varargs method and if it is then the argument values will be appropriately
|
||||
* packaged into an array.
|
||||
* Generate code that handles building the argument values for the specified method.
|
||||
* This method will take account of whether the invoked method is a varargs method
|
||||
* and if it is then the argument values will be appropriately packaged into an array.
|
||||
* @param mv the method visitor where code should be generated
|
||||
* @param cf the current codeflow
|
||||
* @param member the method or constructor for which arguments are being setup
|
||||
@@ -226,7 +227,7 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
|
||||
String[] paramDescriptors = null;
|
||||
boolean isVarargs = false;
|
||||
if (member instanceof Constructor) {
|
||||
Constructor<?> ctor = (Constructor<?>)member;
|
||||
Constructor<?> ctor = (Constructor<?>) member;
|
||||
paramDescriptors = CodeFlow.toDescriptors(ctor.getParameterTypes());
|
||||
isVarargs = ctor.isVarArgs();
|
||||
}
|
||||
@@ -246,25 +247,25 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
|
||||
generateCodeForArgument(mv, cf, arguments[p], paramDescriptors[p]);
|
||||
}
|
||||
|
||||
SpelNodeImpl lastchild = (childCount == 0 ? null : arguments[childCount - 1]);
|
||||
String arraytype = paramDescriptors[paramDescriptors.length - 1];
|
||||
SpelNodeImpl lastChild = (childCount == 0 ? null : arguments[childCount - 1]);
|
||||
String arrayType = paramDescriptors[paramDescriptors.length - 1];
|
||||
// Determine if the final passed argument is already suitably packaged in array
|
||||
// form to be passed to the method
|
||||
if (lastchild != null && lastchild.getExitDescriptor().equals(arraytype)) {
|
||||
generateCodeForArgument(mv, cf, lastchild, paramDescriptors[p]);
|
||||
if (lastChild != null && arrayType.equals(lastChild.getExitDescriptor())) {
|
||||
generateCodeForArgument(mv, cf, lastChild, paramDescriptors[p]);
|
||||
}
|
||||
else {
|
||||
arraytype = arraytype.substring(1); // trim the leading '[', may leave other '['
|
||||
arrayType = arrayType.substring(1); // trim the leading '[', may leave other '['
|
||||
// build array big enough to hold remaining arguments
|
||||
CodeFlow.insertNewArrayCode(mv, childCount - p, arraytype);
|
||||
CodeFlow.insertNewArrayCode(mv, childCount - p, arrayType);
|
||||
// Package up the remaining arguments into the array
|
||||
int arrayindex = 0;
|
||||
while (p < childCount) {
|
||||
SpelNodeImpl child = arguments[p];
|
||||
mv.visitInsn(DUP);
|
||||
CodeFlow.insertOptimalLoad(mv, arrayindex++);
|
||||
generateCodeForArgument(mv, cf, child, arraytype);
|
||||
CodeFlow.insertArrayStore(mv, arraytype);
|
||||
generateCodeForArgument(mv, cf, child, arrayType);
|
||||
CodeFlow.insertArrayStore(mv, arrayType);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
@@ -283,15 +284,16 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
|
||||
protected static void generateCodeForArgument(MethodVisitor mv, CodeFlow cf, SpelNodeImpl argument, String paramDesc) {
|
||||
cf.enterCompilationScope();
|
||||
argument.generateCode(mv, cf);
|
||||
boolean primitiveOnStack = CodeFlow.isPrimitive(cf.lastDescriptor());
|
||||
String lastDesc = cf.lastDescriptor();
|
||||
boolean primitiveOnStack = CodeFlow.isPrimitive(lastDesc);
|
||||
// Check if need to box it for the method reference?
|
||||
if (primitiveOnStack && paramDesc.charAt(0) == 'L') {
|
||||
CodeFlow.insertBoxIfNecessary(mv, cf.lastDescriptor().charAt(0));
|
||||
CodeFlow.insertBoxIfNecessary(mv, lastDesc.charAt(0));
|
||||
}
|
||||
else if (paramDesc.length() == 1 && !primitiveOnStack) {
|
||||
CodeFlow.insertUnboxInsns(mv, paramDesc.charAt(0), cf.lastDescriptor());
|
||||
CodeFlow.insertUnboxInsns(mv, paramDesc.charAt(0), lastDesc);
|
||||
}
|
||||
else if (!cf.lastDescriptor().equals(paramDesc)) {
|
||||
else if (!paramDesc.equals(lastDesc)) {
|
||||
// This would be unnecessary in the case of subtyping (e.g. method takes Number but Integer passed in)
|
||||
CodeFlow.insertCheckCast(mv, paramDesc);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -88,14 +88,13 @@ public class SpelCompiler implements Opcodes {
|
||||
|
||||
|
||||
/**
|
||||
* Attempt compilation of the supplied expression. A check is
|
||||
* made to see if it is compilable before compilation proceeds. The
|
||||
* check involves visiting all the nodes in the expression Ast and
|
||||
* ensuring enough state is known about them that bytecode can
|
||||
* be generated for them.
|
||||
* Attempt compilation of the supplied expression. A check is made to see
|
||||
* if it is compilable before compilation proceeds. The check involves
|
||||
* visiting all the nodes in the expression Ast and ensuring enough state
|
||||
* is known about them that bytecode can be generated for them.
|
||||
* @param expression the expression to compile
|
||||
* @return an instance of the class implementing the compiled expression, or null
|
||||
* if compilation is not possible
|
||||
* @return an instance of the class implementing the compiled expression,
|
||||
* or {@code null} if compilation is not possible
|
||||
*/
|
||||
public CompiledExpression compile(SpelNodeImpl expression) {
|
||||
if (expression.isCompilable()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.expression.TypeConverter;
|
||||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.MethodInvoker;
|
||||
|
||||
/**
|
||||
@@ -141,8 +142,8 @@ public class ReflectionHelper {
|
||||
static ArgumentsMatchInfo compareArgumentsVarargs(
|
||||
List<TypeDescriptor> expectedArgTypes, List<TypeDescriptor> suppliedArgTypes, TypeConverter typeConverter) {
|
||||
|
||||
Assert.isTrue(expectedArgTypes != null && expectedArgTypes.size() > 0,
|
||||
"Expected arguments must at least include one array (the vargargs parameter)");
|
||||
Assert.isTrue(!CollectionUtils.isEmpty(expectedArgTypes),
|
||||
"Expected arguments must at least include one array (the varargs parameter)");
|
||||
Assert.isTrue(expectedArgTypes.get(expectedArgTypes.size() - 1).isArray(),
|
||||
"Final expected argument should be array type (the varargs parameter)");
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -44,6 +44,7 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
|
||||
|
||||
private boolean argumentConversionOccurred = false;
|
||||
|
||||
|
||||
public ReflectiveMethodExecutor(Method method) {
|
||||
this.method = method;
|
||||
if (method.isVarArgs()) {
|
||||
@@ -55,6 +56,7 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Method getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
@@ -68,8 +70,8 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
|
||||
* method (if there is one!). For toString() it may walk as far as Object.
|
||||
*/
|
||||
public Class<?> getPublicDeclaringClass() {
|
||||
if (!computedPublicDeclaringClass) {
|
||||
this.publicDeclaringClass = discoverPublicClass(method, method.getDeclaringClass());
|
||||
if (!this.computedPublicDeclaringClass) {
|
||||
this.publicDeclaringClass = discoverPublicClass(this.method, this.method.getDeclaringClass());
|
||||
this.computedPublicDeclaringClass = true;
|
||||
}
|
||||
return this.publicDeclaringClass;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -93,14 +93,23 @@ public class StandardEvaluationContext implements EvaluationContext {
|
||||
return this.rootObject;
|
||||
}
|
||||
|
||||
public void addConstructorResolver(ConstructorResolver resolver) {
|
||||
ensureConstructorResolversInitialized();
|
||||
this.constructorResolvers.add(this.constructorResolvers.size() - 1, resolver);
|
||||
public void setPropertyAccessors(List<PropertyAccessor> propertyAccessors) {
|
||||
this.propertyAccessors = propertyAccessors;
|
||||
}
|
||||
|
||||
public boolean removeConstructorResolver(ConstructorResolver resolver) {
|
||||
ensureConstructorResolversInitialized();
|
||||
return this.constructorResolvers.remove(resolver);
|
||||
@Override
|
||||
public List<PropertyAccessor> getPropertyAccessors() {
|
||||
ensurePropertyAccessorsInitialized();
|
||||
return this.propertyAccessors;
|
||||
}
|
||||
|
||||
public void addPropertyAccessor(PropertyAccessor accessor) {
|
||||
ensurePropertyAccessorsInitialized();
|
||||
this.propertyAccessors.add(this.propertyAccessors.size() - 1, accessor);
|
||||
}
|
||||
|
||||
public boolean removePropertyAccessor(PropertyAccessor accessor) {
|
||||
return this.propertyAccessors.remove(accessor);
|
||||
}
|
||||
|
||||
public void setConstructorResolvers(List<ConstructorResolver> constructorResolvers) {
|
||||
@@ -113,14 +122,14 @@ public class StandardEvaluationContext implements EvaluationContext {
|
||||
return this.constructorResolvers;
|
||||
}
|
||||
|
||||
public void addMethodResolver(MethodResolver resolver) {
|
||||
ensureMethodResolversInitialized();
|
||||
this.methodResolvers.add(this.methodResolvers.size() - 1, resolver);
|
||||
public void addConstructorResolver(ConstructorResolver resolver) {
|
||||
ensureConstructorResolversInitialized();
|
||||
this.constructorResolvers.add(this.constructorResolvers.size() - 1, resolver);
|
||||
}
|
||||
|
||||
public boolean removeMethodResolver(MethodResolver methodResolver) {
|
||||
ensureMethodResolversInitialized();
|
||||
return this.methodResolvers.remove(methodResolver);
|
||||
public boolean removeConstructorResolver(ConstructorResolver resolver) {
|
||||
ensureConstructorResolversInitialized();
|
||||
return this.constructorResolvers.remove(resolver);
|
||||
}
|
||||
|
||||
public void setMethodResolvers(List<MethodResolver> methodResolvers) {
|
||||
@@ -133,6 +142,16 @@ public class StandardEvaluationContext implements EvaluationContext {
|
||||
return this.methodResolvers;
|
||||
}
|
||||
|
||||
public void addMethodResolver(MethodResolver resolver) {
|
||||
ensureMethodResolversInitialized();
|
||||
this.methodResolvers.add(this.methodResolvers.size() - 1, resolver);
|
||||
}
|
||||
|
||||
public boolean removeMethodResolver(MethodResolver methodResolver) {
|
||||
ensureMethodResolversInitialized();
|
||||
return this.methodResolvers.remove(methodResolver);
|
||||
}
|
||||
|
||||
public void setBeanResolver(BeanResolver beanResolver) {
|
||||
this.beanResolver = beanResolver;
|
||||
}
|
||||
@@ -142,25 +161,6 @@ public class StandardEvaluationContext implements EvaluationContext {
|
||||
return this.beanResolver;
|
||||
}
|
||||
|
||||
public void addPropertyAccessor(PropertyAccessor accessor) {
|
||||
ensurePropertyAccessorsInitialized();
|
||||
this.propertyAccessors.add(this.propertyAccessors.size() - 1, accessor);
|
||||
}
|
||||
|
||||
public boolean removePropertyAccessor(PropertyAccessor accessor) {
|
||||
return this.propertyAccessors.remove(accessor);
|
||||
}
|
||||
|
||||
public void setPropertyAccessors(List<PropertyAccessor> propertyAccessors) {
|
||||
this.propertyAccessors = propertyAccessors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PropertyAccessor> getPropertyAccessors() {
|
||||
ensurePropertyAccessorsInitialized();
|
||||
return this.propertyAccessors;
|
||||
}
|
||||
|
||||
public void setTypeLocator(TypeLocator typeLocator) {
|
||||
Assert.notNull(typeLocator, "TypeLocator must not be null");
|
||||
this.typeLocator = typeLocator;
|
||||
@@ -169,7 +169,7 @@ public class StandardEvaluationContext implements EvaluationContext {
|
||||
@Override
|
||||
public TypeLocator getTypeLocator() {
|
||||
if (this.typeLocator == null) {
|
||||
this.typeLocator = new StandardTypeLocator();
|
||||
this.typeLocator = new StandardTypeLocator();
|
||||
}
|
||||
return this.typeLocator;
|
||||
}
|
||||
@@ -244,6 +244,7 @@ public class StandardEvaluationContext implements EvaluationContext {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ensurePropertyAccessorsInitialized() {
|
||||
if (this.propertyAccessors == null) {
|
||||
initializePropertyAccessors();
|
||||
@@ -258,6 +259,20 @@ public class StandardEvaluationContext implements EvaluationContext {
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureConstructorResolversInitialized() {
|
||||
if (this.constructorResolvers == null) {
|
||||
initializeConstructorResolvers();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void initializeConstructorResolvers() {
|
||||
if (this.constructorResolvers == null) {
|
||||
List<ConstructorResolver> defaultResolvers = new ArrayList<ConstructorResolver>();
|
||||
defaultResolvers.add(new ReflectiveConstructorResolver());
|
||||
this.constructorResolvers = defaultResolvers;
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureMethodResolversInitialized() {
|
||||
if (this.methodResolvers == null) {
|
||||
initializeMethodResolvers();
|
||||
@@ -273,18 +288,4 @@ public class StandardEvaluationContext implements EvaluationContext {
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureConstructorResolversInitialized() {
|
||||
if (this.constructorResolvers == null) {
|
||||
initializeConstructorResolvers();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void initializeConstructorResolvers() {
|
||||
if (this.constructorResolvers == null) {
|
||||
List<ConstructorResolver> defaultResolvers = new ArrayList<ConstructorResolver>();
|
||||
defaultResolvers.add(new ReflectiveConstructorResolver());
|
||||
this.constructorResolvers = defaultResolvers;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -67,8 +67,9 @@ public class StandardTypeConverter implements TypeConverter {
|
||||
return this.conversionService.convert(value, sourceType, targetType);
|
||||
}
|
||||
catch (ConversionException ex) {
|
||||
throw new SpelEvaluationException(
|
||||
ex, SpelMessage.TYPE_CONVERSION_ERROR, sourceType.toString(), targetType.toString());
|
||||
throw new SpelEvaluationException(ex, SpelMessage.TYPE_CONVERSION_ERROR,
|
||||
(sourceType != null ? sourceType.toString() : (value != null ? value.getClass().getName() : "null")),
|
||||
targetType.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user