Skip to content

Commit

Permalink
Auto-adapt reflective arguments in case of vararg array type mismatch
Browse files Browse the repository at this point in the history
Issue: SPR-13328
  • Loading branch information
jhoeller authored and Benjamin Reed committed Jul 28, 2022
1 parent fff372a commit b5430fe
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package org.springframework.aop.framework;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

Expand All @@ -25,6 +27,7 @@
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.target.SingletonTargetSource;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

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


/**
* Adapt the given arguments to the target signature in the given method,
* if necessary: in particular, if a given vararg argument array does not
* match the array type of the declared vararg parameter in the method.
* @param method the target method
* @param arguments the given arguments
* @return a cloned argument array, or the original if no adaptation is needed
* @since 4.2.3
*/
static Object[] adaptArgumentsIfNecessary(Method method, Object... arguments) {
if (method.isVarArgs() && !ObjectUtils.isEmpty(arguments)) {
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length == arguments.length) {
int varargIndex = paramTypes.length - 1;
Class<?> varargType = paramTypes[varargIndex];
if (varargType.isArray()) {
Object varargArray = arguments[varargIndex];
if (varargArray instanceof Object[] && !varargType.isInstance(varargArray)) {
Object[] newArguments = new Object[arguments.length];
System.arraycopy(arguments, 0, newArguments, 0, varargIndex);
Class<?> targetElementType = varargType.getComponentType();
int varargLength = Array.getLength(varargArray);
Object newVarargArray = Array.newInstance(targetElementType, varargLength);
System.arraycopy(varargArray, 0, newVarargArray, 0, varargLength);
newArguments[varargIndex] = newVarargArray;
return newArguments;
}
}
}
}
return arguments;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2015 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.
Expand Down Expand Up @@ -109,7 +109,7 @@ protected ReflectiveMethodInvocation(
this.target = target;
this.targetClass = targetClass;
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.arguments = arguments;
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}

Expand Down

0 comments on commit b5430fe

Please # to comment.