org.nakedobjects.metamodel.specloader.internal.introspector.MethodFinderUtils Maven / Gradle / Ivy
The newest version!
package org.nakedobjects.metamodel.specloader.internal.introspector;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.nakedobjects.metamodel.commons.lang.JavaClassUtils;
import org.nakedobjects.metamodel.commons.lang.WrapperUtils;
import org.nakedobjects.metamodel.facets.MethodScope;
/**
* TODO: duplication with {@link WrapperUtils} and {@link PrimitiveUtils}.
*/
public final class MethodFinderUtils {
private static Map, Class> boxedClasses = new HashMap, Class>();
static {
// TODO: there is a better way of doing this in 1.6 using TypeMirror - this is just
// for java 1.1 compatibility - replace after code fork.
boxedClasses.put(boolean.class, Boolean.class);
boxedClasses.put(char.class, Character.class);
boxedClasses.put(byte.class, Byte.class);
boxedClasses.put(short.class, Short.class);
boxedClasses.put(int.class, Integer.class);
boxedClasses.put(long.class, Long.class);
boxedClasses.put(float.class, Float.class);
boxedClasses.put(double.class, Double.class);
boxedClasses.put(void.class, Void.class);
}
private MethodFinderUtils() {}
/**
* Searches the supplied array of methods for specific method and returns it, also removing it from
* supplied array if found (by setting to null).
*
*
* Any methods that do not meet the search criteria are left in the array of methods.
*
*
* The search algorithm is:
*
* - has the specified prefix
* - has the specified return type, or void if canBeVoid is true (but see below)
* - has the specified number of parameters
*
* If the returnType is specified as null then the return type is ignored.
*
* @param forClass
* @param name
* @param returnType
* @param paramTypes
* the set of parameters the method should have, if null then is ignored
* @return Method
*/
public static Method removeMethod(
final Method[] methods,
final MethodScope methodScope,
final String name,
final Class returnType,
final Class[] paramTypes) {
method: for (int i = 0; i < methods.length; i++) {
if (methods[i] == null) {
continue;
}
final Method method = methods[i];
final int modifiers = method.getModifiers();
// check for public modifier
if (!Modifier.isPublic(modifiers)) {
continue;
}
// check for static modifier
if (!inScope(methodScope, method)) {
continue;
}
// check for name
if (!method.getName().equals(name)) {
continue;
}
// check for return type
if (returnType != null && returnType != method.getReturnType()) {
continue;
}
// check params (if required)
if (paramTypes != null) {
final Class[] parameterTypes = method.getParameterTypes();
if (paramTypes.length != parameterTypes.length) {
continue;
}
for (int c = 0; c < paramTypes.length; c++) {
if ((paramTypes[c] != null) && (paramTypes[c] != parameterTypes[c])) {
continue method;
}
}
}
methods[i] = null;
return method;
}
return null;
}
public static boolean inScope(final MethodScope methodScope, final Method method) {
final boolean isStatic = JavaClassUtils.isStatic(method);
return isStatic && methodScope == MethodScope.CLASS || !isStatic && methodScope == MethodScope.OBJECT;
}
/**
* Searches the supplied array of methods for all specific methods and returns them, also removing them
* from supplied array if found.
*
*
* Any methods that do not meet the search criteria are left in the array of methods.
*
*
* The search algorithm is:
*
* - has the specified prefix
* - has the specified return type, or void if canBeVoid is true (but see below)
* - has the specified number of parameters
*
* If the returnType is specified as null then the return type is ignored.
*
* @param forClass
* @param name
* @param returnType
* @param paramTypes
* the set of parameters the method should have, if null then is ignored
* @return Method
*/
public static List removeMethods(
final Method[] methods,
final MethodScope forClass,
final String prefix,
final Class returnType,
final boolean canBeVoid,
final int paramCount) {
final List validMethods = new ArrayList();
for (int i = 0; i < methods.length; i++) {
if (methods[i] == null) {
continue;
}
final Method method = methods[i];
if (!inScope(forClass, method)) {
continue;
}
final boolean goodPrefix = method.getName().startsWith(prefix);
final boolean goodCount = method.getParameterTypes().length == paramCount;
final Class type = method.getReturnType();
final boolean goodReturn = returnTypeCompatible(returnType, canBeVoid, type);
if (goodPrefix && goodCount && goodReturn) {
validMethods.add(method);
methods[i] = null;
}
}
return validMethods;
}
private static boolean returnTypeCompatible(final Class returnType, final boolean canBeVoid, final Class type) {
if (returnType == null) {
return true;
}
if (canBeVoid && (type == void.class)) {
return true;
}
if (type.isPrimitive()) {
return returnType.isAssignableFrom(boxedClasses.get(type));
}
return (returnType.isAssignableFrom(type));
}
/**
* From the supplied method array, finds but does not remove methods that have the required prefix,
* and adds to the supplied candidates vector.
*/
public static void findPrefixedInstanceMethods(final Method[] methods, final String prefix, final List candidates) {
for (int i = 0; i < methods.length; i++) {
if (methods[i] == null) {
continue;
}
final Method method = methods[i];
if (JavaClassUtils.isStatic(method)) {
continue;
}
final boolean goodPrefix = method.getName().startsWith(prefix);
final boolean goodCount = method.getParameterTypes().length == 0;
if (goodPrefix && goodCount) {
candidates.add(method);
}
}
}
}
// Copyright (c) Naked Objects Group Ltd.