1 /* 2 * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package com.sun.beans.finder; 26 27 import java.util.HashMap; 28 import java.util.Map; 29 30 /** 31 * This abstract class provides functionality 32 * to find a public method or constructor 33 * with specified parameter types. 34 * It supports a variable number of parameters. 35 * 36 * @since 1.7 37 * 38 * @author Sergey A. Malenkov 39 */ 40 abstract class AbstractFinder<T> { 41 private final Class<?>[] args; 42 43 /** 44 * Creates finder for array of classes of arguments. 45 * If a particular element of array equals {@code null}, 46 * than the appropriate pair of classes 47 * does not take into consideration. 48 * 49 * @param args array of classes of arguments 50 */ 51 protected AbstractFinder(Class<?>[] args) { 52 this.args = args; 53 } 54 55 /** 56 * Returns an array of {@code Class} objects 57 * that represent the formal parameter types of the method. 58 * Returns an empty array if the method takes no parameters. 59 * 60 * @param method the object that represents method 61 * @return the parameter types of the method 62 */ 63 protected abstract Class<?>[] getParameters(T method); 64 65 /** 66 * Returns {@code true} if and only if the method 67 * was declared to take a variable number of arguments. 68 * 69 * @param method the object that represents method 70 * @return {@code true} if the method was declared 71 * to take a variable number of arguments; 72 * {@code false} otherwise 73 */ 74 protected abstract boolean isVarArgs(T method); 75 76 /** 77 * Checks validness of the method. 78 * At least the valid method should be public. 79 * 80 * @param method the object that represents method 81 * @return {@code true} if the method is valid, 82 * {@code false} otherwise 83 */ 84 protected abstract boolean isValid(T method); 85 86 /** 87 * Performs a search in the {@code methods} array. 88 * The one method is selected from the array of the valid methods. 89 * The list of parameters of the selected method shows 90 * the best correlation with the list of arguments 91 * specified at class initialization. 92 * If more than one method is both accessible and applicable 93 * to a method invocation, it is necessary to choose one 94 * to provide the descriptor for the run-time method dispatch. 95 * The most specific method should be chosen. 96 * 97 * @param methods the array of methods to search within 98 * @return the object that represents found method 99 * @throws NoSuchMethodException if no method was found or several 100 * methods meet the search criteria 101 * @see #isAssignable 102 */ 103 final T find(T[] methods) throws NoSuchMethodException { 104 Map<T, Class<?>[]> map = new HashMap<T, Class<?>[]>(); 105 106 T oldMethod = null; 107 Class<?>[] oldParams = null; 108 boolean ambiguous = false; 109 110 for (T newMethod : methods) { 111 if (isValid(newMethod)) { 112 Class<?>[] newParams = getParameters(newMethod); 113 if (newParams.length == this.args.length) { 114 PrimitiveWrapperMap.replacePrimitivesWithWrappers(newParams); 115 if (isAssignable(newParams, this.args)) { 116 if (oldMethod == null) { 117 oldMethod = newMethod; 118 oldParams = newParams; 119 } else { 120 boolean useNew = isAssignable(oldParams, newParams); 121 boolean useOld = isAssignable(newParams, oldParams); 122 123 if (useOld == useNew) { 124 ambiguous = true; 125 } else if (useNew) { 126 oldMethod = newMethod; 127 oldParams = newParams; 128 ambiguous = false; 129 } 130 } 131 } 132 } 133 if (isVarArgs(newMethod)) { 134 int length = newParams.length - 1; 135 if (length <= this.args.length) { 136 Class<?>[] array = new Class<?>[this.args.length]; 137 System.arraycopy(newParams, 0, array, 0, length); 138 if (length < this.args.length) { 139 Class<?> type = newParams[length].getComponentType(); 140 if (type.isPrimitive()) { 141 type = PrimitiveWrapperMap.getType(type.getName()); 142 } 143 for (int i = length; i < this.args.length; i++) { 144 array[i] = type; 145 } 146 } 147 map.put(newMethod, array); 148 } 149 } 150 } 151 } 152 for (T newMethod : methods) { 153 Class<?>[] newParams = map.get(newMethod); 154 if (newParams != null) { 155 if (isAssignable(newParams, this.args)) { 156 if (oldMethod == null) { 157 oldMethod = newMethod; 158 oldParams = newParams; 159 } else { 160 boolean useNew = isAssignable(oldParams, newParams); 161 boolean useOld = isAssignable(newParams, oldParams); 162 163 if (useOld == useNew) { 164 if (oldParams == map.get(oldMethod)) { 165 ambiguous = true; 166 } 167 } else if (useNew) { 168 oldMethod = newMethod; 169 oldParams = newParams; 170 ambiguous = false; 171 } 172 } 173 } 174 } 175 } 176 177 if (ambiguous) { 178 throw new NoSuchMethodException("Ambiguous methods are found"); 179 } 180 if (oldMethod == null) { 181 throw new NoSuchMethodException("Method is not found"); 182 } | 1 /* 2 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package com.sun.beans.finder; 26 27 import java.lang.reflect.Executable; 28 import java.lang.reflect.Modifier; 29 30 import java.util.HashMap; 31 import java.util.Map; 32 33 /** 34 * This abstract class provides functionality 35 * to find a public method or constructor 36 * with specified parameter types. 37 * It supports a variable number of parameters. 38 * 39 * @since 1.7 40 * 41 * @author Sergey A. Malenkov 42 */ 43 abstract class AbstractFinder<T extends Executable> { 44 private final Class<?>[] args; 45 46 /** 47 * Creates finder for array of classes of arguments. 48 * If a particular element of array equals {@code null}, 49 * than the appropriate pair of classes 50 * does not take into consideration. 51 * 52 * @param args array of classes of arguments 53 */ 54 protected AbstractFinder(Class<?>[] args) { 55 this.args = args; 56 } 57 58 /** 59 * Checks validness of the method. 60 * At least the valid method should be public. 61 * 62 * @param method the object that represents method 63 * @return {@code true} if the method is valid, 64 * {@code false} otherwise 65 */ 66 protected boolean isValid(T method) { 67 return Modifier.isPublic(method.getModifiers()); 68 } 69 70 /** 71 * Performs a search in the {@code methods} array. 72 * The one method is selected from the array of the valid methods. 73 * The list of parameters of the selected method shows 74 * the best correlation with the list of arguments 75 * specified at class initialization. 76 * If more than one method is both accessible and applicable 77 * to a method invocation, it is necessary to choose one 78 * to provide the descriptor for the run-time method dispatch. 79 * The most specific method should be chosen. 80 * 81 * @param methods the array of methods to search within 82 * @return the object that represents found method 83 * @throws NoSuchMethodException if no method was found or several 84 * methods meet the search criteria 85 * @see #isAssignable 86 */ 87 final T find(T[] methods) throws NoSuchMethodException { 88 Map<T, Class<?>[]> map = new HashMap<T, Class<?>[]>(); 89 90 T oldMethod = null; 91 Class<?>[] oldParams = null; 92 boolean ambiguous = false; 93 94 for (T newMethod : methods) { 95 if (isValid(newMethod)) { 96 Class<?>[] newParams = newMethod.getParameterTypes(); 97 if (newParams.length == this.args.length) { 98 PrimitiveWrapperMap.replacePrimitivesWithWrappers(newParams); 99 if (isAssignable(newParams, this.args)) { 100 if (oldMethod == null) { 101 oldMethod = newMethod; 102 oldParams = newParams; 103 } else { 104 boolean useNew = isAssignable(oldParams, newParams); 105 boolean useOld = isAssignable(newParams, oldParams); 106 107 if (useOld && useNew) { 108 // only if parameters are equal 109 useNew = !newMethod.isSynthetic(); 110 useOld = !oldMethod.isSynthetic(); 111 } 112 if (useOld == useNew) { 113 ambiguous = true; 114 } else if (useNew) { 115 oldMethod = newMethod; 116 oldParams = newParams; 117 ambiguous = false; 118 } 119 } 120 } 121 } 122 if (newMethod.isVarArgs()) { 123 int length = newParams.length - 1; 124 if (length <= this.args.length) { 125 Class<?>[] array = new Class<?>[this.args.length]; 126 System.arraycopy(newParams, 0, array, 0, length); 127 if (length < this.args.length) { 128 Class<?> type = newParams[length].getComponentType(); 129 if (type.isPrimitive()) { 130 type = PrimitiveWrapperMap.getType(type.getName()); 131 } 132 for (int i = length; i < this.args.length; i++) { 133 array[i] = type; 134 } 135 } 136 map.put(newMethod, array); 137 } 138 } 139 } 140 } 141 for (T newMethod : methods) { 142 Class<?>[] newParams = map.get(newMethod); 143 if (newParams != null) { 144 if (isAssignable(newParams, this.args)) { 145 if (oldMethod == null) { 146 oldMethod = newMethod; 147 oldParams = newParams; 148 } else { 149 boolean useNew = isAssignable(oldParams, newParams); 150 boolean useOld = isAssignable(newParams, oldParams); 151 152 if (useOld && useNew) { 153 // only if parameters are equal 154 useNew = !newMethod.isSynthetic(); 155 useOld = !oldMethod.isSynthetic(); 156 } 157 if (useOld == useNew) { 158 if (oldParams == map.get(oldMethod)) { 159 ambiguous = true; 160 } 161 } else if (useNew) { 162 oldMethod = newMethod; 163 oldParams = newParams; 164 ambiguous = false; 165 } 166 } 167 } 168 } 169 } 170 171 if (ambiguous) { 172 throw new NoSuchMethodException("Ambiguous methods are found"); 173 } 174 if (oldMethod == null) { 175 throw new NoSuchMethodException("Method is not found"); 176 } |