blob: 923d88e9051cc1f61a0527df90dea30aa1c0479b [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 groovy.lang.GString;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
/**
* @author Alex.Tkachman
*/
public class CachedClass {
private CachedClass cachedSuperClass;
private CachedMethod[] methods;
public final Class cachedClass;
public final boolean isArray;
public final boolean isPrimitive;
public final int modifiers;
int distance = -1;
public final boolean isInterface;
public final boolean isNumber;
CachedClass(Class klazz) {
cachedClass = klazz;
isArray = klazz.isArray();
isPrimitive = klazz.isPrimitive();
modifiers = klazz.getModifiers();
isInterface = klazz.isInterface();
isNumber = Number.class.isAssignableFrom(klazz);
}
public synchronized CachedClass getCachedSuperClass() {
if (cachedSuperClass == null)
cachedSuperClass = ReflectionCache.getCachedClass(cachedClass.getSuperclass());
return cachedSuperClass;
}
public synchronized CachedMethod[] getMethods() {
if (methods == null) {
final Method[] declaredMethods = cachedClass.getDeclaredMethods();
methods = new CachedMethod[declaredMethods.length];
for (int i = 0; i != methods.length; ++i)
methods[i] = ReflectionCache.getCachedMethod(declaredMethods[i]);
}
return methods;
}
public Method searchMethods(String name, CachedClass[] parameterTypes) {
CachedMethod[] methods = getMethods();
Method res = null;
for (int i = 0; i < methods.length; i++) {
CachedMethod m = methods[i];
if (m.cachedMethod.getName().equals(name)
&& ReflectionCache.arrayContentsEq(parameterTypes, m.getParameterTypes())
&& (res == null || res.getReturnType().isAssignableFrom(m.cachedMethod.getReturnType())))
res = m.cachedMethod;
}
return res;
}
public int getModifiers() {
return modifiers;
}
/**
* Coerces a GString instance into String if needed
*
* @return the coerced argument
*/
protected Object coerceGString(Object argument) {
if (cachedClass != String.class) return argument;
if (!(argument instanceof GString)) return argument;
return argument.toString();
}
// PRECONDITION:
// !ReflectionCache.isAssignableFrom(parameterType, argument.getClass())
protected Object coerceNumber(Object argument) {
if (argument instanceof Number && (isNumber || isPrimitive)) { // Number types
Object oldArgument = argument;
boolean wasDouble = false;
boolean wasFloat = false;
Class param = cachedClass;
if (param == Byte.class || param == Byte.TYPE) {
argument = new Byte(((Number) argument).byteValue());
} else if (param == Double.class || param == Double.TYPE) {
wasDouble = true;
argument = new Double(((Number) argument).doubleValue());
} else if (param == Float.class || param == Float.TYPE) {
wasFloat = true;
argument = new Float(((Number) argument).floatValue());
} else if (param == Integer.class || param == Integer.TYPE) {
argument = new Integer(((Number) argument).intValue());
} else if (param == Long.class || param == Long.TYPE) {
argument = new Long(((Number) argument).longValue());
} else if (param == Short.class || param == Short.TYPE) {
argument = new Short(((Number) argument).shortValue());
} else if (param == BigDecimal.class) {
argument = new BigDecimal(String.valueOf((Number) argument));
} else if (param == BigInteger.class) {
argument = new BigInteger(String.valueOf((Number) argument));
}
if (oldArgument instanceof BigDecimal) {
BigDecimal oldbd = (BigDecimal) oldArgument;
boolean throwException = false;
if (wasDouble) {
Double d = (Double) argument;
if (d.isInfinite()) throwException = true;
} else if (wasFloat) {
Float f = (Float) argument;
if (f.isInfinite()) throwException = true;
} else {
BigDecimal newbd = new BigDecimal(String.valueOf((Number) argument));
throwException = !oldArgument.equals(newbd);
}
if (throwException)
throw new IllegalArgumentException(param + " out of range while converting from BigDecimal");
}
}
return argument;
}
protected Object coerceArray(Object argument) {
if (!isArray) return argument;
Class argumentClass = argument.getClass();
if (!argumentClass.isArray()) return argument;
Class paramComponent = cachedClass.getComponentType();
if (paramComponent.isPrimitive()) {
if (paramComponent == boolean.class && argumentClass == Boolean[].class) {
argument = DefaultTypeTransformation.convertToBooleanArray(argument);
} else if (paramComponent == byte.class && argumentClass == Byte[].class) {
argument = DefaultTypeTransformation.convertToByteArray(argument);
} else if (paramComponent == char.class && argumentClass == Character[].class) {
argument = DefaultTypeTransformation.convertToCharArray(argument);
} else if (paramComponent == short.class && argumentClass == Short[].class) {
argument = DefaultTypeTransformation.convertToShortArray(argument);
} else if (paramComponent == int.class && argumentClass == Integer[].class) {
argument = DefaultTypeTransformation.convertToIntArray(argument);
} else if (paramComponent == long.class &&
(argumentClass == Long[].class || argumentClass == Integer[].class)) {
argument = DefaultTypeTransformation.convertToLongArray(argument);
} else if (paramComponent == float.class &&
(argumentClass == Float[].class || argumentClass == Integer[].class)) {
argument = DefaultTypeTransformation.convertToFloatArray(argument);
} else if (paramComponent == double.class &&
(argumentClass == Double[].class || argumentClass == Float[].class
|| BigDecimal[].class.isAssignableFrom(argumentClass))) {
argument = DefaultTypeTransformation.convertToDoubleArray(argument);
}
} else if (paramComponent == String.class && argument instanceof GString[]) {
GString[] strings = (GString[]) argument;
String[] ret = new String[strings.length];
for (int i = 0; i < strings.length; i++) {
ret[i] = strings[i].toString();
}
argument = ret;
}
return argument;
}
public int getSuperClassDistance() {
synchronized (cachedClass) {
if (distance == -1) {
int distance = 0;
for (Class klazz=cachedClass; klazz != null; klazz = klazz.getSuperclass()) {
distance++;
}
this.distance = distance;
}
return distance;
}
}
}