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
  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         }