Polishing
This commit is contained in:
parent
04f765506e
commit
ef1e17fd15
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2014 the original author or authors.
|
* Copyright 2002-2015 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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-2015 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -445,15 +445,14 @@ public class ConstructorReference extends SpelNodeImpl {
|
||||||
public void generateCode(MethodVisitor mv, CodeFlow cf) {
|
public void generateCode(MethodVisitor mv, CodeFlow cf) {
|
||||||
ReflectiveConstructorExecutor executor = ((ReflectiveConstructorExecutor) this.cachedExecutor);
|
ReflectiveConstructorExecutor executor = ((ReflectiveConstructorExecutor) this.cachedExecutor);
|
||||||
Constructor<?> constructor = executor.getConstructor();
|
Constructor<?> constructor = executor.getConstructor();
|
||||||
String classSlashedDescriptor = constructor.getDeclaringClass().getName().replace('.', '/');
|
String classDesc = constructor.getDeclaringClass().getName().replace('.', '/');
|
||||||
mv.visitTypeInsn(NEW, classSlashedDescriptor);
|
mv.visitTypeInsn(NEW, classDesc);
|
||||||
mv.visitInsn(DUP);
|
mv.visitInsn(DUP);
|
||||||
// children[0] is the type of the constructor, don't want to include that in argument processing
|
// children[0] is the type of the constructor, don't want to include that in argument processing
|
||||||
SpelNodeImpl[] arguments = new SpelNodeImpl[children.length - 1];
|
SpelNodeImpl[] arguments = new SpelNodeImpl[children.length - 1];
|
||||||
System.arraycopy(children, 1, arguments, 0, children.length - 1);
|
System.arraycopy(children, 1, arguments, 0, children.length - 1);
|
||||||
generateCodeForArguments(mv, cf, constructor, arguments);
|
generateCodeForArguments(mv, cf, constructor, arguments);
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, classSlashedDescriptor, "<init>",
|
mv.visitMethodInsn(INVOKESPECIAL, classDesc, "<init>", CodeFlow.createSignatureDescriptor(constructor), false);
|
||||||
CodeFlow.createSignatureDescriptor(constructor), false);
|
|
||||||
cf.pushDescriptor(this.exitTypeDescriptor);
|
cf.pushDescriptor(this.exitTypeDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2014 the original author or authors.
|
* Copyright 2002-2015 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -33,15 +33,15 @@ import org.springframework.expression.spel.support.ReflectionHelper;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function reference is of the form "#someFunction(a,b,c)". Functions may be defined in
|
* A function reference is of the form "#someFunction(a,b,c)". Functions may be defined
|
||||||
* the context prior to the expression being evaluated or within the expression itself
|
* in the context prior to the expression being evaluated or within the expression itself
|
||||||
* using a lambda function definition. For example: Lambda function definition in an
|
* using a lambda function definition. For example: Lambda function definition in an
|
||||||
* expression: "(#max = {|x,y|$x>$y?$x:$y};max(2,3))" Calling context defined function:
|
* expression: "(#max = {|x,y|$x>$y?$x:$y};max(2,3))" Calling context defined function:
|
||||||
* "#isEven(37)". Functions may also be static java methods, registered in the context
|
* "#isEven(37)". Functions may also be static java methods, registered in the context
|
||||||
* prior to invocation of the expression.
|
* prior to invocation of the expression.
|
||||||
*
|
*
|
||||||
* <p>Functions are very simplistic, the arguments are not part of the definition (right
|
* <p>Functions are very simplistic, the arguments are not part of the definition
|
||||||
* now), so the names must be unique.
|
* (right now), so the names must be unique.
|
||||||
*
|
*
|
||||||
* @author Andy Clement
|
* @author Andy Clement
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
|
@ -72,7 +72,8 @@ public class FunctionReference extends SpelNodeImpl {
|
||||||
|
|
||||||
// Two possibilities: a lambda function or a Java static method registered as a function
|
// Two possibilities: a lambda function or a Java static method registered as a function
|
||||||
if (!(value.getValue() instanceof Method)) {
|
if (!(value.getValue() instanceof Method)) {
|
||||||
throw new SpelEvaluationException(SpelMessage.FUNCTION_REFERENCE_CANNOT_BE_INVOKED, this.name, value.getClass());
|
throw new SpelEvaluationException(
|
||||||
|
SpelMessage.FUNCTION_REFERENCE_CANNOT_BE_INVOKED, this.name, value.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -113,7 +114,8 @@ public class FunctionReference extends SpelNodeImpl {
|
||||||
argumentConversionOccurred = ReflectionHelper.convertAllArguments(converter, functionArgs, method);
|
argumentConversionOccurred = ReflectionHelper.convertAllArguments(converter, functionArgs, method);
|
||||||
}
|
}
|
||||||
if (method.isVarArgs()) {
|
if (method.isVarArgs()) {
|
||||||
functionArgs = ReflectionHelper.setupArgumentsForVarargsInvocation(method.getParameterTypes(), functionArgs);
|
functionArgs =
|
||||||
|
ReflectionHelper.setupArgumentsForVarargsInvocation(method.getParameterTypes(), functionArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -160,13 +162,12 @@ public class FunctionReference extends SpelNodeImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCompilable() {
|
public boolean isCompilable() {
|
||||||
if (this.method == null || argumentConversionOccurred) {
|
if (this.method == null || this.argumentConversionOccurred) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int methodModifiers = this.method.getModifiers();
|
int methodModifiers = this.method.getModifiers();
|
||||||
if (!Modifier.isStatic(methodModifiers) ||
|
if (!Modifier.isStatic(methodModifiers) || !Modifier.isPublic(methodModifiers) ||
|
||||||
!Modifier.isPublic(methodModifiers) ||
|
!Modifier.isPublic(this.method.getDeclaringClass().getModifiers())) {
|
||||||
!Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (SpelNodeImpl child : this.children) {
|
for (SpelNodeImpl child : this.children) {
|
||||||
|
@ -179,9 +180,9 @@ public class FunctionReference extends SpelNodeImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generateCode(MethodVisitor mv,CodeFlow cf) {
|
public void generateCode(MethodVisitor mv,CodeFlow cf) {
|
||||||
String methodDeclaringClassSlashedDescriptor = this.method.getDeclaringClass().getName().replace('.', '/');
|
String classDesc = this.method.getDeclaringClass().getName().replace('.', '/');
|
||||||
generateCodeForArguments(mv, cf, method, this.children);
|
generateCodeForArguments(mv, cf, this.method, this.children);
|
||||||
mv.visitMethodInsn(INVOKESTATIC, methodDeclaringClassSlashedDescriptor, this.method.getName(),
|
mv.visitMethodInsn(INVOKESTATIC, classDesc, this.method.getName(),
|
||||||
CodeFlow.createSignatureDescriptor(this.method), false);
|
CodeFlow.createSignatureDescriptor(this.method), false);
|
||||||
cf.pushDescriptor(this.exitTypeDescriptor);
|
cf.pushDescriptor(this.exitTypeDescriptor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,14 +239,14 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
|
||||||
// The final parameter may or may not need packaging into an array, or nothing may
|
// The final parameter may or may not need packaging into an array, or nothing may
|
||||||
// have been passed to satisfy the varargs and so something needs to be built.
|
// have been passed to satisfy the varargs and so something needs to be built.
|
||||||
int p = 0; // Current supplied argument being processed
|
int p = 0; // Current supplied argument being processed
|
||||||
int childcount = arguments.length;
|
int childCount = arguments.length;
|
||||||
|
|
||||||
// Fulfill all the parameter requirements except the last one
|
// Fulfill all the parameter requirements except the last one
|
||||||
for (p = 0; p < paramDescriptors.length - 1; p++) {
|
for (p = 0; p < paramDescriptors.length - 1; p++) {
|
||||||
generateCodeForArgument(mv, cf, arguments[p], paramDescriptors[p]);
|
generateCodeForArgument(mv, cf, arguments[p], paramDescriptors[p]);
|
||||||
}
|
}
|
||||||
|
|
||||||
SpelNodeImpl lastchild = (childcount == 0 ? null : arguments[childcount-1]);
|
SpelNodeImpl lastchild = (childCount == 0 ? null : arguments[childCount - 1]);
|
||||||
String arraytype = paramDescriptors[paramDescriptors.length - 1];
|
String arraytype = paramDescriptors[paramDescriptors.length - 1];
|
||||||
// Determine if the final passed argument is already suitably packaged in array
|
// Determine if the final passed argument is already suitably packaged in array
|
||||||
// form to be passed to the method
|
// form to be passed to the method
|
||||||
|
@ -256,10 +256,10 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
|
||||||
else {
|
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
|
// 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
|
// Package up the remaining arguments into the array
|
||||||
int arrayindex = 0;
|
int arrayindex = 0;
|
||||||
while (p < childcount) {
|
while (p < childCount) {
|
||||||
SpelNodeImpl child = arguments[p];
|
SpelNodeImpl child = arguments[p];
|
||||||
mv.visitInsn(DUP);
|
mv.visitInsn(DUP);
|
||||||
CodeFlow.insertOptimalLoad(mv, arrayindex++);
|
CodeFlow.insertOptimalLoad(mv, arrayindex++);
|
||||||
|
@ -280,20 +280,20 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
|
||||||
* Ask an argument to generate its bytecode and then follow it up
|
* Ask an argument to generate its bytecode and then follow it up
|
||||||
* with any boxing/unboxing/checkcasting to ensure it matches the expected parameter descriptor.
|
* with any boxing/unboxing/checkcasting to ensure it matches the expected parameter descriptor.
|
||||||
*/
|
*/
|
||||||
protected static void generateCodeForArgument(MethodVisitor mv, CodeFlow cf, SpelNodeImpl argument, String paramDescriptor) {
|
protected static void generateCodeForArgument(MethodVisitor mv, CodeFlow cf, SpelNodeImpl argument, String paramDesc) {
|
||||||
cf.enterCompilationScope();
|
cf.enterCompilationScope();
|
||||||
argument.generateCode(mv, cf);
|
argument.generateCode(mv, cf);
|
||||||
boolean primitiveOnStack = CodeFlow.isPrimitive(cf.lastDescriptor());
|
boolean primitiveOnStack = CodeFlow.isPrimitive(cf.lastDescriptor());
|
||||||
// Check if need to box it for the method reference?
|
// Check if need to box it for the method reference?
|
||||||
if (primitiveOnStack && paramDescriptor.charAt(0) == 'L') {
|
if (primitiveOnStack && paramDesc.charAt(0) == 'L') {
|
||||||
CodeFlow.insertBoxIfNecessary(mv, cf.lastDescriptor().charAt(0));
|
CodeFlow.insertBoxIfNecessary(mv, cf.lastDescriptor().charAt(0));
|
||||||
}
|
}
|
||||||
else if (paramDescriptor.length() == 1 && !primitiveOnStack) {
|
else if (paramDesc.length() == 1 && !primitiveOnStack) {
|
||||||
CodeFlow.insertUnboxInsns(mv, paramDescriptor.charAt(0), cf.lastDescriptor());
|
CodeFlow.insertUnboxInsns(mv, paramDesc.charAt(0), cf.lastDescriptor());
|
||||||
}
|
}
|
||||||
else if (!cf.lastDescriptor().equals(paramDescriptor)) {
|
else if (!cf.lastDescriptor().equals(paramDesc)) {
|
||||||
// This would be unnecessary in the case of subtyping (e.g. method takes Number but Integer passed in)
|
// This would be unnecessary in the case of subtyping (e.g. method takes Number but Integer passed in)
|
||||||
CodeFlow.insertCheckCast(mv, paramDescriptor);
|
CodeFlow.insertCheckCast(mv, paramDesc);
|
||||||
}
|
}
|
||||||
cf.exitCompilationScope();
|
cf.exitCompilationScope();
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,8 +238,10 @@ public class ReflectionHelper {
|
||||||
* @return true if some kind of conversion occurred on the argument
|
* @return true if some kind of conversion occurred on the argument
|
||||||
* @throws SpelEvaluationException if there is a problem with conversion
|
* @throws SpelEvaluationException if there is a problem with conversion
|
||||||
*/
|
*/
|
||||||
public static boolean convertAllArguments(TypeConverter converter, Object[] arguments, Method method) throws SpelEvaluationException {
|
public static boolean convertAllArguments(TypeConverter converter, Object[] arguments, Method method)
|
||||||
Integer varargsPosition = method.isVarArgs() ? method.getParameterTypes().length-1:null;
|
throws SpelEvaluationException {
|
||||||
|
|
||||||
|
Integer varargsPosition = (method.isVarArgs() ? method.getParameterTypes().length - 1 : null);
|
||||||
return convertArguments(converter, arguments, method, varargsPosition);
|
return convertArguments(converter, arguments, method, varargsPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2014 the original author or authors.
|
* Copyright 2002-2015 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -21,7 +21,6 @@ import java.util.Map;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
|
||||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||||
import org.springframework.beans.factory.support.ManagedMap;
|
import org.springframework.beans.factory.support.ManagedMap;
|
||||||
|
@ -134,21 +133,25 @@ class ViewControllerBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private RootBeanDefinition getRedirectView(Element element, HttpStatus status, Object source) {
|
private RootBeanDefinition getRedirectView(Element element, HttpStatus status, Object source) {
|
||||||
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
|
RootBeanDefinition redirectView = new RootBeanDefinition(RedirectView.class);
|
||||||
cavs.addIndexedArgumentValue(0, element.getAttribute("redirect-url"));
|
|
||||||
RootBeanDefinition redirectView = new RootBeanDefinition(RedirectView.class, cavs, null);
|
|
||||||
redirectView.setSource(source);
|
redirectView.setSource(source);
|
||||||
|
redirectView.getConstructorArgumentValues().addIndexedArgumentValue(0, element.getAttribute("redirect-url"));
|
||||||
|
|
||||||
if (status != null) {
|
if (status != null) {
|
||||||
redirectView.getPropertyValues().add("statusCode", status);
|
redirectView.getPropertyValues().add("statusCode", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.hasAttribute("context-relative")) {
|
if (element.hasAttribute("context-relative")) {
|
||||||
redirectView.getPropertyValues().add("contextRelative", element.getAttribute("context-relative"));
|
redirectView.getPropertyValues().add("contextRelative", element.getAttribute("context-relative"));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
redirectView.getPropertyValues().add("contextRelative", true);
|
redirectView.getPropertyValues().add("contextRelative", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.hasAttribute("keep-query-params")) {
|
if (element.hasAttribute("keep-query-params")) {
|
||||||
redirectView.getPropertyValues().add("propagateQueryParams", element.getAttribute("keep-query-params"));
|
redirectView.getPropertyValues().add("propagateQueryParams", element.getAttribute("keep-query-params"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirectView;
|
return redirectView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue