jdk/src/share/classes/com/sun/beans/finder/AbstractFinder.java

Print this page


   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         }