org.easymock.internal.ReflectionUtils Maven / Gradle / Ivy
Show all versions of easymock Show documentation
/**
* Copyright 2001-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.
* 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.easymock.internal;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @author Henri Tremblay
*/
public final class ReflectionUtils {
private static final Map, Class> primitiveToWrapperType = new HashMap, Class>(8);
static {
primitiveToWrapperType.put(boolean.class, Boolean.class);
primitiveToWrapperType.put(byte.class, Byte.class);
primitiveToWrapperType.put(short.class, Short.class);
primitiveToWrapperType.put(char.class, Character.class);
primitiveToWrapperType.put(int.class, Integer.class);
primitiveToWrapperType.put(long.class, Long.class);
primitiveToWrapperType.put(float.class, Float.class);
primitiveToWrapperType.put(double.class, Double.class);
}
public static final Method OBJECT_EQUALS = getDeclaredMethod(Object.class, "equals",
new Class[] { Object.class });
public static final Method OBJECT_HASHCODE = getDeclaredMethod(Object.class, "hashCode", (Class[]) null);
public static final Method OBJECT_TOSTRING = getDeclaredMethod(Object.class, "toString", (Class[]) null);
public static final Method OBJECT_FINALIZE = getDeclaredMethod(Object.class, "finalize", (Class[]) null);
// ///CLOVER:OFF
private ReflectionUtils() {
}
// ///CLOVER:ON
/**
* Attempt to find a {@link Method} on the supplied class with the supplied
* name and no parameters. Searches all superclasses up to
* {@code Object}.
*
* Returns {@code null} if no {@link Method} can be found.
*
* @param clazz
* the class to introspect
* @param name
* the name of the method
* @return the Method object, or {@code null} if none found
*/
public static Method findMethod(Class clazz, String name) {
return findMethod(clazz, name, (Class[]) null);
}
/**
* Attempt to find a {@link Method} on the supplied class with the supplied
* name and parameter types. Searches all superclasses up to
* {@code Object}.
*
* Returns {@code null} if no {@link Method} can be found.
*
* @param clazz
* the class to introspect
* @param name
* the name of the method
* @param paramTypes
* the parameter types of the method (may be {@code null} to
* indicate any signature)
* @return the Method object, or {@code null} if none found
*/
public static Method findMethod(Class clazz, String name, Class... paramTypes) {
Class searchType = clazz;
while (searchType != null) {
Method[] methods = searchType.getDeclaredMethods();
Method result = null;
for (Method method : methods) {
// Private methods can't be mocked so just skip them
if (Modifier.isPrivate(method.getModifiers())) {
continue;
}
// Skip bridges because we never mock them. We mock the method underneath
if (method.isBridge()) {
continue;
}
if (name.equals(method.getName())) {
if (paramTypes == null) {
if (result != null) {
throw new RuntimeException("Ambiguous name: More than one method are named "
+ name);
}
result = method;
} else if (Arrays.equals(paramTypes, method.getParameterTypes())) {
return method;
}
}
}
if (result != null) {
return result;
}
searchType = searchType.getSuperclass();
}
return null;
}
/**
* Returns a constructor that contains {@code objs} as arguments.
*
*
* We could not do something like {@code clazz.getConstructor(objs.class())}
* because that would require casting all the passed arguments to the exact
* parameter types of the desired constructor.
*
* @param clazz
* class on which we are searching the constructor
* @param
* type of the class searched
* @param objs
* list of arguments of the constructor
* @return a constructor with the arguments in {@code objs}
* @throws NoSuchMethodException
* when the constructor with {@code args} does not exist or is
* ambiguous
*/
@SuppressWarnings("unchecked")
public static Constructor getConstructor(Class clazz, Object... objs)
throws NoSuchMethodException {
Constructor ret = null;
for (Constructor classConstructor : clazz.getDeclaredConstructors()) {
if (isMatchingConstructor(classConstructor, objs)) {
if (ret != null) {
// We had already found a constructor, so this is ambiguous
throw new IllegalArgumentException("Ambiguity in the constructors for " + clazz.getName()
+ ".");
}
// This unsafe cast is guaranteed to be correct by Class#getConstructors()
ret = (Constructor) classConstructor;
}
}
if (ret != null) {
return ret;
}
// Not found
throw new NoSuchMethodException("Couldn't find constructor for class " + clazz.getName());
}
/**
* Returns true if objects in {@code objs} are eligible to be passed to
* {@code classConstructor}.
*/
private static boolean isMatchingConstructor(Constructor classConstructor, Object... objs) {
if (Modifier.isPrivate(classConstructor.getModifiers())) {
return false;
}
Class[] parameterTypes = classConstructor.getParameterTypes();
if (parameterTypes.length != objs.length) {
return false;
}
for (int i = 0; i < objs.length; ++i) {
Class parameterType = parameterTypes[i];
// If the parameter is a primitive, we need to get the boxed equivalent type
if (parameterType.isPrimitive()) {
parameterType = wrapPrimitive(parameterType);
}
// Check if parameter type matches
if (!parameterType.isInstance(objs[i])) {
return false;
}
}
return true;
}
/**
* Given a primitive type, returns its boxed equivalent. For instance, given
* {@code int}, returns {@code Integer}.
*
* @param parameterType
* the primitive type
* @return the boxed equivalent
*/
private static Class wrapPrimitive(Class parameterType) {
return primitiveToWrapperType.get(parameterType);
}
/**
* Basically calls getDeclaredMethod on a Class but wraps the
* NoSuchMethodException into a Runtime.
*
* @param clazz
* class on which the getDeclaredMethod is called
* @param name
* method name
* @param paramTypes
* method parameters
* @return the method searched
*/
public static Method getDeclaredMethod(Class clazz, String name,
Class... paramTypes) {
try {
return clazz.getDeclaredMethod(name, paramTypes);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}