blob: a8766d1a9afb043b78b76486d73a2268a1e28082 [file] [log] [blame]
/*
* Copyright 2003-2007 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.reflection;
import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.runtime.MetaClassHelper;
import java.lang.reflect.Array;
public class ParameterTypes
{
protected Class [] nativeParamTypes;
protected CachedClass [] parameterTypes;
public ParameterTypes () {
}
public ParameterTypes(Class pt []) {
nativeParamTypes = pt;
}
public ParameterTypes(CachedClass[] parameterTypes) {
this.parameterTypes = parameterTypes;
}
public CachedClass[] getParameterTypes() {
if (parameterTypes == null) {
synchronized (this) {
if (parameterTypes != null)
return parameterTypes;
Class [] npt = nativeParamTypes == null ? getPT() : nativeParamTypes;
CachedClass [] pt = new CachedClass [npt.length];
for (int i = 0; i != npt.length; ++i)
pt[i] = ReflectionCache.getCachedClass(npt[i]);
nativeParamTypes = npt;
parameterTypes = pt;
}
}
return parameterTypes;
}
public Class[] getNativeParameterTypes() {
if (nativeParamTypes == null) {
synchronized (this) {
if (nativeParamTypes != null)
return nativeParamTypes;
Class [] npt;
if (parameterTypes != null) {
npt = new Class [parameterTypes.length];
for (int i = 0; i != parameterTypes.length; ++i) {
npt[i] = parameterTypes[i].getCachedClass();
}
}
else
npt = getPT ();
nativeParamTypes = npt;
}
}
return nativeParamTypes;
}
Class[] getPT() { return null; }
public boolean isVargsMethod(Object[] arguments) {
getParameterTypes();
if (parameterTypes.length == 0) return false;
final int lenMinus1 = parameterTypes.length - 1;
if (!parameterTypes[lenMinus1].isArray) return false;
// -1 because the varg part is optional
if (lenMinus1 == arguments.length) return true;
if (lenMinus1 > arguments.length) return false;
if (arguments.length > parameterTypes.length) return true;
// only case left is arguments.length == parameterTypes.length
Object last = arguments[arguments.length - 1];
if (last == null) return true;
Class clazz = last.getClass();
return !clazz.equals(parameterTypes[lenMinus1].getCachedClass());
}
public Object[] coerceArgumentsToClasses(Object[] argumentArray) {
getParameterTypes();
// correct argumentArray's length
if (argumentArray == null) {
argumentArray = MetaClassHelper.EMPTY_ARRAY;
} else if (parameterTypes.length == 1 && argumentArray.length == 0) {
if (isVargsMethod(argumentArray)) {
argumentArray = new Object[]{Array.newInstance(parameterTypes[0].getCachedClass().getComponentType(), 0)};
}
else
argumentArray = MetaClassHelper.ARRAY_WITH_NULL;
} else if (isVargsMethod(argumentArray)) {
argumentArray = fitToVargs(argumentArray, parameterTypes);
}
//correct Type
for (int i = 0; i < argumentArray.length; i++) {
Object argument = argumentArray[i];
if (argument == null) continue;
CachedClass parameterType = parameterTypes[i];
if (ReflectionCache.isAssignableFrom(parameterType.getCachedClass(), argument.getClass())) continue;
argument = parameterType.coerceGString(argument);
argument = parameterType.coerceNumber(argument);
argument = parameterType.coerceArray(argument);
argumentArray[i] = argument;
}
return argumentArray;
}
/**
* this method is called when the number of arguments to a method is greater than 1
* and if the method is a vargs method. This method will then transform the given
* arguments to make the method callable
*
* @param argumentArray the arguments used to call the method
* @param paramTypes the types of the paramters the method takes
*/
private static Object[] fitToVargs(Object[] argumentArray, CachedClass[] paramTypes) {
Class vargsClass = ReflectionCache.autoboxType(paramTypes[paramTypes.length - 1].getCachedClass().getComponentType());
if (argumentArray.length == paramTypes.length - 1) {
// the vargs argument is missing, so fill it with an empty array
Object[] newArgs = new Object[paramTypes.length];
System.arraycopy(argumentArray, 0, newArgs, 0, argumentArray.length);
Object vargs = MetaClassHelper.makeArray(null, vargsClass, 0);
newArgs[newArgs.length - 1] = vargs;
return newArgs;
} else if (argumentArray.length == paramTypes.length) {
// the number of arguments is correct, but if the last argument
// is no array we have to wrap it in a array. if the last argument
// is null, then we don't have to do anything
Object lastArgument = argumentArray[argumentArray.length - 1];
if (lastArgument != null && !lastArgument.getClass().isArray()) {
// no array so wrap it
Object vargs = MetaClassHelper.makeArray(lastArgument, vargsClass, 1);
System.arraycopy(argumentArray, argumentArray.length - 1, vargs, 0, 1);
argumentArray[argumentArray.length - 1] = vargs;
return argumentArray;
} else {
// we may have to box the arguemnt!
return argumentArray;
}
} else if (argumentArray.length > paramTypes.length) {
// the number of arguments is too big, wrap all exceeding elements
// in an array, but keep the old elements that are no vargs
Object[] newArgs = new Object[paramTypes.length];
// copy arguments that are not a varg
System.arraycopy(argumentArray, 0, newArgs, 0, paramTypes.length - 1);
// create a new array for the vargs and copy them
int numberOfVargs = argumentArray.length - paramTypes.length;
Object vargs = MetaClassHelper.makeCommonArray(argumentArray, paramTypes.length - 1, vargsClass);
newArgs[newArgs.length - 1] = vargs;
return newArgs;
} else {
throw new GroovyBugError("trying to call a vargs method without enough arguments");
}
}
}