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
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.Member;
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 Member> {
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 * Returns an array of {@code Class} objects
60 * that represent the formal parameter types of the method.
61 * Returns an empty array if the method takes no parameters.
62 *
63 * @param method the object that represents method
67
68 /**
69 * Returns {@code true} if and only if the method
70 * was declared to take a variable number of arguments.
71 *
72 * @param method the object that represents method
73 * @return {@code true} if the method was declared
74 * to take a variable number of arguments;
75 * {@code false} otherwise
76 */
77 protected abstract boolean isVarArgs(T method);
78
79 /**
80 * Checks validness of the method.
81 * At least the valid method should be public.
82 *
83 * @param method the object that represents method
84 * @return {@code true} if the method is valid,
85 * {@code false} otherwise
86 */
87 protected boolean isValid(T method) {
88 return Modifier.isPublic(method.getModifiers());
89 }
90
91 /**
92 * Performs a search in the {@code methods} array.
93 * The one method is selected from the array of the valid methods.
94 * The list of parameters of the selected method shows
95 * the best correlation with the list of arguments
96 * specified at class initialization.
97 * If more than one method is both accessible and applicable
98 * to a method invocation, it is necessary to choose one
99 * to provide the descriptor for the run-time method dispatch.
100 * The most specific method should be chosen.
101 *
102 * @param methods the array of methods to search within
103 * @return the object that represents found method
104 * @throws NoSuchMethodException if no method was found or several
105 * methods meet the search criteria
106 * @see #isAssignable
107 */
108 final T find(T[] methods) throws NoSuchMethodException {
109 Map<T, Class<?>[]> map = new HashMap<T, Class<?>[]>();
110
111 T oldMethod = null;
112 Class<?>[] oldParams = null;
113 boolean ambiguous = false;
114
115 for (T newMethod : methods) {
116 if (isValid(newMethod)) {
117 Class<?>[] newParams = getParameters(newMethod);
118 if (newParams.length == this.args.length) {
119 PrimitiveWrapperMap.replacePrimitivesWithWrappers(newParams);
120 if (isAssignable(newParams, this.args)) {
121 if (oldMethod == null) {
122 oldMethod = newMethod;
123 oldParams = newParams;
124 } else {
125 boolean useNew = isAssignable(oldParams, newParams);
126 boolean useOld = isAssignable(newParams, oldParams);
127
128 if (useOld && useNew) {
129 // only if parameters are equal
130 useNew = !newMethod.isSynthetic();
131 useOld = !oldMethod.isSynthetic();
132 }
133 if (useOld == useNew) {
134 ambiguous = true;
135 } else if (useNew) {
136 oldMethod = newMethod;
137 oldParams = newParams;
138 ambiguous = false;
139 }
140 }
141 }
142 }
143 if (isVarArgs(newMethod)) {
144 int length = newParams.length - 1;
145 if (length <= this.args.length) {
146 Class<?>[] array = new Class<?>[this.args.length];
147 System.arraycopy(newParams, 0, array, 0, length);
148 if (length < this.args.length) {
149 Class<?> type = newParams[length].getComponentType();
150 if (type.isPrimitive()) {
151 type = PrimitiveWrapperMap.getType(type.getName());
152 }
153 for (int i = length; i < this.args.length; i++) {
154 array[i] = type;
155 }
156 }
157 map.put(newMethod, array);
158 }
159 }
160 }
161 }
162 for (T newMethod : methods) {
163 Class<?>[] newParams = map.get(newMethod);
164 if (newParams != null) {
165 if (isAssignable(newParams, this.args)) {
166 if (oldMethod == null) {
167 oldMethod = newMethod;
168 oldParams = newParams;
169 } else {
170 boolean useNew = isAssignable(oldParams, newParams);
171 boolean useOld = isAssignable(newParams, oldParams);
172
173 if (useOld && useNew) {
174 // only if parameters are equal
175 useNew = !newMethod.isSynthetic();
176 useOld = !oldMethod.isSynthetic();
177 }
178 if (useOld == useNew) {
179 if (oldParams == map.get(oldMethod)) {
180 ambiguous = true;
181 }
182 } else if (useNew) {
183 oldMethod = newMethod;
184 oldParams = newParams;
185 ambiguous = false;
186 }
187 }
188 }
189 }
190 }
191
192 if (ambiguous) {
193 throw new NoSuchMethodException("Ambiguous methods are found");
194 }
195 if (oldMethod == null) {
196 throw new NoSuchMethodException("Method is not found");
197 }
|