001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020package org.apache.isis.core.commons.lang; 021 022import java.lang.reflect.Method; 023import java.lang.reflect.Modifier; 024import java.util.ArrayList; 025import java.util.List; 026 027import org.apache.isis.core.metamodel.methodutils.MethodScope; 028 029public class MethodUtil { 030 031 private MethodUtil(){} 032 033 public static void invoke(final List<Method> methods, final Object object) { 034 for (final Method method : methods) { 035 MethodExtensions.invoke(method, object); 036 } 037 } 038 039 /** 040 * Searches the supplied array of methods for specific method and returns 041 * it, also removing it from supplied array if found (by setting to 042 * <tt>null</tt>). 043 * 044 * <p> 045 * Any methods that do not meet the search criteria are left in the array of 046 * methods. 047 * 048 * <p> 049 * The search algorithm is as specified in 050 * {@link MethodUtil#findMethodIndex(List, MethodScope, String, Class, Class[])}. 051 */ 052 public static Method removeMethod(final List<Method> methods, final MethodScope methodScope, final String name, final Class<?> returnType, final Class<?>[] paramTypes) { 053 final int idx = MethodUtil.findMethodIndex(methods, methodScope, name, returnType, paramTypes); 054 if (idx != -1) { 055 final Method method = methods.get(idx); 056 methods.set(idx, null); 057 return method; 058 } 059 return null; 060 } 061 062 /** 063 * Searches the supplied array of methods for specific method and returns 064 * its index, otherwise returns <tt>-1</tt>. 065 * 066 * <p> 067 * The search algorithm is: 068 * <ul> 069 * <li>has the specified prefix</li> 070 * <li>has the specified return type, or <tt>void</tt> if canBeVoid is 071 * <tt>true</tt> (but see below)</li> 072 * <li>has the specified number of parameters</li> 073 * </ul> 074 * If the returnType is specified as null then the return type is ignored. 075 */ 076 public static int findMethodIndex(final List<Method> methods, final MethodScope methodScope, final String name, final Class<?> returnType, final Class<?>[] paramTypes) { 077 int idx = -1; 078 method: for (int i = 0; i < methods.size(); i++) { 079 if (methods.get(i) == null) { 080 continue; 081 } 082 083 final Method method = methods.get(i); 084 final int modifiers = method.getModifiers(); 085 086 // check for public modifier 087 if (!Modifier.isPublic(modifiers)) { 088 continue; 089 } 090 091 // check for static modifier 092 if (!inScope(method, methodScope)) { 093 continue; 094 } 095 096 // check for name 097 if (!method.getName().equals(name)) { 098 continue; 099 } 100 101 // check for return type 102 if (returnType != null && returnType != method.getReturnType()) { 103 continue; 104 } 105 106 // check params (if required) 107 if (paramTypes != null) { 108 final Class<?>[] parameterTypes = method.getParameterTypes(); 109 if (paramTypes.length != parameterTypes.length) { 110 continue; 111 } 112 113 for (int c = 0; c < paramTypes.length; c++) { 114 if ((paramTypes[c] != null) && (paramTypes[c] != parameterTypes[c])) { 115 continue method; 116 } 117 } 118 } 119 idx = i; 120 break; 121 } 122 return idx; 123 } 124 125 public static boolean inScope(final Method extendee, final MethodScope methodScope) { 126 final boolean isStatic = MethodExtensions.isStatic(extendee); 127 return isStatic && methodScope == MethodScope.CLASS || !isStatic && methodScope == MethodScope.OBJECT; 128 } 129 130 /** 131 * Searches the supplied array of methods for all specific methods and 132 * returns them, also removing them from supplied array if found. 133 * 134 * <p> 135 * Any methods that do not meet the search criteria are left in the array of 136 * methods. 137 * 138 * <p> 139 * The search algorithm is: 140 * <ul> 141 * <li>has the specified prefix</li> 142 * <li>has the specified return type, or <tt>void</tt> if canBeVoid is 143 * <tt>true</tt> (but see below)</li> 144 * <li>has the specified number of parameters</li> 145 * </ul> 146 * If the returnType is specified as null then the return type is ignored. 147 * 148 * @param forClass 149 * @param name 150 * @param returnType 151 * @param paramTypes 152 * the set of parameters the method should have, if null then is 153 * ignored 154 * @return Method 155 */ 156 public static List<Method> removeMethods(final List<Method> methods, final MethodScope forClass, final String prefix, final Class<?> returnType, final boolean canBeVoid, final int paramCount) { 157 158 final List<Method> validMethods = new ArrayList<Method>(); 159 160 for (int i = 0; i < methods.size(); i++) { 161 if (methods.get(i) == null) { 162 continue; 163 } 164 165 final Method method = methods.get(i); 166 167 if (!inScope(method, forClass)) { 168 continue; 169 } 170 171 final boolean goodPrefix = method.getName().startsWith(prefix); 172 173 final boolean goodCount = method.getParameterTypes().length == paramCount; 174 final Class<?> type = method.getReturnType(); 175 final boolean goodReturn = ClassExtensions.isCompatibleAsReturnType(returnType, canBeVoid, type); 176 177 if (goodPrefix && goodCount && goodReturn) { 178 validMethods.add(method); 179 methods.set(i, null); 180 } 181 } 182 return validMethods; 183 } 184 185 /** 186 * From the supplied method array, finds but <i>does not remove</i> methods 187 * that have the required prefix, and adds to the supplied candidates 188 * vector. 189 */ 190 public static void findPrefixedInstanceMethods(final Method[] methods, final String prefix, final List<Method> candidates) { 191 for (final Method method : methods) { 192 if (method == null) { 193 continue; 194 } 195 196 if (MethodExtensions.isStatic(method)) { 197 continue; 198 } 199 200 final boolean goodPrefix = method.getName().startsWith(prefix); 201 final boolean goodCount = method.getParameterTypes().length == 0; 202 203 if (goodPrefix && goodCount) { 204 candidates.add(method); 205 } 206 } 207 } 208 209}