/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.isis.core.commons.lang;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import org.apache.isis.core.metamodel.methodutils.MethodScope;
public class MethodUtil {
private MethodUtil(){}
public static void invoke(final List<Method> methods, final Object object) {
for (final Method method : methods) {
MethodExtensions.invoke(method, object);
}
}
/**
* Searches the supplied array of methods for specific method and returns
* it, also removing it from supplied array if found (by setting to
* <tt>null</tt>).
*
* <p>
* Any methods that do not meet the search criteria are left in the array of
* methods.
*
* <p>
* The search algorithm is as specified in
* {@link MethodUtil#findMethodIndex(List, MethodScope, String, Class, Class[])}.
*/
public static Method removeMethod(final List<Method> methods, final MethodScope methodScope, final String name, final Class<?> returnType, final Class<?>[] paramTypes) {
final int idx = MethodUtil.findMethodIndex(methods, methodScope, name, returnType, paramTypes);
if (idx != -1) {
final Method method = methods.get(idx);
methods.set(idx, null);
return method;
}
return null;
}
/**
* Searches the supplied array of methods for specific method and returns
* its index, otherwise returns <tt>-1</tt>.
*
* <p>
* The search algorithm is:
* <ul>
* <li>has the specified prefix</li>
* <li>has the specified return type, or <tt>void</tt> if canBeVoid is
* <tt>true</tt> (but see below)</li>
* <li>has the specified number of parameters</li>
* </ul>
* If the returnType is specified as null then the return type is ignored.
*/
private static int findMethodIndex(final List<Method> methods, final MethodScope methodScope, final String name, final Class<?> returnType, final Class<?>[] paramTypes) {
int idx = -1;
method: for (int i = 0; i < methods.size(); i++) {
if (methods.get(i) == null) {
continue;
}
final Method method = methods.get(i);
final int modifiers = method.getModifiers();
// check for public modifier
if (!Modifier.isPublic(modifiers)) {
continue;
}
// check for static modifier
if (!inScope(method, methodScope)) {
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;
}
}
}
idx = i;
break;
}
return idx;
}
public static boolean inScope(final Method extendee, final MethodScope methodScope) {
final boolean isStatic = MethodExtensions.isStatic(extendee);
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.
*
* <p>
* Any methods that do not meet the search criteria are left in the array of
* methods.
*
* <p>
* The search algorithm is:
* <ul>
* <li>has the specified prefix</li>
* <li>has the specified return type, or <tt>void</tt> if canBeVoid is
* <tt>true</tt> (but see below)</li>
* <li>has the specified number of parameters</li>
* </ul>
* 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<Method> removeMethods(
final List<Method> methods,
final MethodScope forClass,
final String prefix,
final Class<?> returnType,
final boolean canBeVoid,
final int paramCount) {
final List<Method> validMethods = new ArrayList<Method>();
for (int i = 0; i < methods.size(); i++) {
final Method method = methods.get(i);
if (method == null) {
continue;
}
if (!inScope(method, forClass)) {
continue;
}
final boolean goodPrefix = method.getName().startsWith(prefix);
final boolean goodCount = method.getParameterTypes().length == paramCount;
final Class<?> type = method.getReturnType();
final boolean goodReturn = ClassExtensions.isCompatibleAsReturnType(returnType, canBeVoid, type);
if (goodPrefix && goodCount && goodReturn) {
validMethods.add(method);
methods.set(i, null);
}
}
return validMethods;
}
}