001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.isis.core.progmodel.facets; 018 019import java.lang.annotation.Annotation; 020import java.lang.reflect.Method; 021import java.lang.reflect.Modifier; 022import java.util.ArrayList; 023import java.util.List; 024 025import org.apache.isis.core.metamodel.facetapi.MethodRemover; 026import org.apache.isis.core.metamodel.methodutils.MethodScope; 027 028public final class MethodFinderUtils { 029 030 private MethodFinderUtils() { 031 } 032 033 public static Method findMethodWithOrWithoutParameters(final Class<?> type, final MethodScope classMethod, final String name, final Class<?> returnType, final Class<?>[] paramTypes) { 034 Method method = MethodFinderUtils.findMethod(type, classMethod, name, returnType, paramTypes); 035 if (method == null) { 036 method = MethodFinderUtils.findMethod(type, classMethod, name, returnType, MethodPrefixBasedFacetFactoryAbstract.NO_PARAMETERS_TYPES); 037 } 038 return method; 039 } 040 041 /** 042 * Returns a specific public methods that: have the specified prefix; have 043 * the specified return type (or some subtype), and has the 044 * specified number of parameters. 045 * 046 * <p> 047 * If the returnType is specified as null then the return type is ignored. 048 * If void.class is passed in, then searches for void methods. 049 * 050 * <p> 051 * If the parameter type array is null, is also not checked. 052 */ 053 public static Method findMethod( 054 final Class<?> type, 055 final MethodScope methodScope, 056 final String name, 057 final Class<?> returnType, 058 final Class<?>[] paramTypes) { 059 060 Method method; 061 try { 062 method = type.getMethod(name, paramTypes); 063 } catch (final SecurityException e) { 064 return null; 065 } catch (final NoSuchMethodException e) { 066 return null; 067 } 068 069 final int modifiers = method.getModifiers(); 070 071 if (!Modifier.isPublic(modifiers)) { 072 return null; 073 } 074 075 // check for scope modifier 076 if (!methodScope.matchesScopeOf(method)) { 077 return null; 078 } 079 080 if (!method.getName().equals(name)) { 081 return null; 082 } 083 084 if (returnType != null && !returnType.isAssignableFrom(method.getReturnType())) { 085 return null; 086 } 087 088 if (paramTypes != null) { 089 final Class<?>[] parameterTypes = method.getParameterTypes(); 090 if (paramTypes.length != parameterTypes.length) { 091 return null; 092 } 093 094 for (int c = 0; c < paramTypes.length; c++) { 095 if ((paramTypes[c] != null) && (paramTypes[c] != parameterTypes[c])) { 096 return null; 097 } 098 } 099 } 100 101 return method; 102 } 103 104 protected static boolean doesNotMatchScope(final MethodScope methodScope, final Method method) { 105 return methodScope.doesNotMatchScope(method); 106 } 107 108 public static Method findMethod(final Class<?> type, final MethodScope methodScope, final String name, final Class<?> returnType) { 109 try { 110 final Method[] methods = type.getMethods(); 111 for (final Method method2 : methods) { 112 final Method method = method2; 113 final int modifiers = method.getModifiers(); 114 // check for public modifier 115 if (!Modifier.isPublic(modifiers)) { 116 continue; 117 } 118 119 // check correct scope (static vs instance) 120 if (!methodScope.matchesScopeOf(method)) { 121 continue; 122 } 123 124 // check for name 125 if (!method.getName().equals(name)) { 126 continue; 127 } 128 129 // check for return type 130 if (returnType != null && returnType != method.getReturnType()) { 131 continue; 132 } 133 return method; 134 } 135 } catch (final SecurityException e) { 136 return null; 137 } 138 return null; 139 } 140 141 public static List<Method> findMethodsWithAnnotation(final Class<?> type, final MethodScope methodScope, final Class<? extends Annotation> annotationClass) { 142 143 final List<Method> methods = new ArrayList<Method>(); 144 145 // Validate arguments 146 if ((type == null) || (methodScope == null) || (annotationClass == null)) { 147 throw new IllegalArgumentException("One or more arguments are 'null' valued"); 148 } 149 150 // Find methods annotated with the specified annotation 151 for (final Method method : type.getMethods()) { 152 if (!methodScope.matchesScopeOf(method)) { 153 continue; 154 } 155 156 if (method.isAnnotationPresent(annotationClass)) { 157 methods.add(method); 158 } 159 } 160 161 return methods; 162 } 163 164 public static void removeMethod(final MethodRemover methodRemover, final Method method) { 165 if (methodRemover != null && method != null) { 166 methodRemover.removeMethod(method); 167 } 168 } 169 170 public static Class<?>[] paramTypesOrNull(final Class<?> type) { 171 return type == null ? null : new Class[] { type }; 172 } 173 174 public static boolean allParametersOfSameType(final Class<?>[] params) { 175 final Class<?> firstParam = params[0]; 176 for (int i = 1; i < params.length; i++) { 177 if (params[i] != firstParam) { 178 return false; 179 } 180 } 181 return true; 182 } 183 184}