Skip to content

Commit 36d0015

Browse files
jhoellerBenjamin Reed
authored and
Benjamin Reed
committed
Auto-adapt reflective arguments in case of vararg array type mismatch
Issue: SPR-13328
1 parent adfac79 commit 36d0015

File tree

4 files changed

+46
-8
lines changed

4 files changed

+46
-8
lines changed

spring-aop/src/main/java/org/springframework/aop/ProxyMethodInvocation.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -57,14 +57,14 @@ public interface ProxyMethodInvocation extends MethodInvocation {
5757
* @return an invocable clone of this invocation.
5858
* {@code proceed()} can be called once per clone.
5959
*/
60-
MethodInvocation invocableClone(Object[] arguments);
60+
MethodInvocation invocableClone(Object... arguments);
6161

6262
/**
6363
* Set the arguments to be used on subsequent invocations in the any advice
6464
* in this chain.
6565
* @param arguments the argument array
6666
*/
67-
void setArguments(Object[] arguments);
67+
void setArguments(Object... arguments);
6868

6969
/**
7070
* Add the specified user attribute with the given value to this invocation.

spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.aop.framework;
1818

19+
import java.lang.reflect.Array;
20+
import java.lang.reflect.Method;
1921
import java.lang.reflect.Proxy;
2022
import java.util.Arrays;
2123

@@ -25,6 +27,7 @@
2527
import org.springframework.aop.support.AopUtils;
2628
import org.springframework.aop.target.SingletonTargetSource;
2729
import org.springframework.util.Assert;
30+
import org.springframework.util.ObjectUtils;
2831

2932
/**
3033
* Utility methods for AOP proxy factories.
@@ -161,4 +164,38 @@ public static boolean equalsAdvisors(AdvisedSupport a, AdvisedSupport b) {
161164
return Arrays.equals(a.getAdvisors(), b.getAdvisors());
162165
}
163166

167+
168+
/**
169+
* Adapt the given arguments to the target signature in the given method,
170+
* if necessary: in particular, if a given vararg argument array does not
171+
* match the array type of the declared vararg parameter in the method.
172+
* @param method the target method
173+
* @param arguments the given arguments
174+
* @return a cloned argument array, or the original if no adaptation is needed
175+
* @since 4.2.3
176+
*/
177+
static Object[] adaptArgumentsIfNecessary(Method method, Object... arguments) {
178+
if (method.isVarArgs() && !ObjectUtils.isEmpty(arguments)) {
179+
Class<?>[] paramTypes = method.getParameterTypes();
180+
if (paramTypes.length == arguments.length) {
181+
int varargIndex = paramTypes.length - 1;
182+
Class<?> varargType = paramTypes[varargIndex];
183+
if (varargType.isArray()) {
184+
Object varargArray = arguments[varargIndex];
185+
if (varargArray instanceof Object[] && !varargType.isInstance(varargArray)) {
186+
Object[] newArguments = new Object[arguments.length];
187+
System.arraycopy(arguments, 0, newArguments, 0, varargIndex);
188+
Class<?> targetElementType = varargType.getComponentType();
189+
int varargLength = Array.getLength(varargArray);
190+
Object newVarargArray = Array.newInstance(targetElementType, varargLength);
191+
System.arraycopy(varargArray, 0, newVarargArray, 0, varargLength);
192+
newArguments[varargIndex] = newVarargArray;
193+
return newArguments;
194+
}
195+
}
196+
}
197+
}
198+
return arguments;
199+
}
200+
164201
}

spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,8 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
198198
// We can skip creating a MethodInvocation: just invoke the target directly
199199
// Note that the final invoker must be an InvokerInterceptor so we know it does
200200
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
201-
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
201+
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
202+
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
202203
}
203204
else {
204205
// We need to create a method invocation...

spring-aop/src/main/java/org/springframework/aop/framework/ReflectiveMethodInvocation.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -109,7 +109,7 @@ protected ReflectiveMethodInvocation(
109109
this.target = target;
110110
this.targetClass = targetClass;
111111
this.method = BridgeMethodResolver.findBridgedMethod(method);
112-
this.arguments = arguments;
112+
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
113113
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
114114
}
115115

@@ -145,7 +145,7 @@ public final Object[] getArguments() {
145145
}
146146

147147
@Override
148-
public void setArguments(Object[] arguments) {
148+
public void setArguments(Object... arguments) {
149149
this.arguments = arguments;
150150
}
151151

@@ -219,7 +219,7 @@ public MethodInvocation invocableClone() {
219219
* @see java.lang.Object#clone()
220220
*/
221221
@Override
222-
public MethodInvocation invocableClone(Object[] arguments) {
222+
public MethodInvocation invocableClone(Object... arguments) {
223223
// Force initialization of the user attributes Map,
224224
// for having a shared Map reference in the clone.
225225
if (this.userAttributes == null) {

0 commit comments

Comments
 (0)