jdk/src/share/classes/java/beans/ReflectionUtils.java
author malenkov
Wed, 09 Jul 2008 19:29:07 +0400
changeset 1281 b2928adc218e
parent 2 90ce3da70b43
child 1844 ac2cf8242428
permissions -rw-r--r--
4994637: LTP: java.beans.java_util_Map_PersistenceDelegate: ConcurrentModificationException Reviewed-by: peterz, loneid
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
     2
 * Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
90ce3da70b43 Initial load
duke
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Sun designates this
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
90ce3da70b43 Initial load
duke
parents:
diff changeset
     9
 * by Sun in the LICENSE file that accompanied this code.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    21
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    22
 * CA 95054 USA or visit www.sun.com if you need additional information or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    23
 * have any questions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
package java.beans;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
import java.lang.reflect.Constructor;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
import java.lang.reflect.Field;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
import java.lang.reflect.Method;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
import java.lang.reflect.Modifier;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
import java.lang.ref.Reference;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
import java.lang.ref.SoftReference;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
import java.util.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
import com.sun.beans.ObjectHandler;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
import sun.reflect.misc.MethodUtil;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
import sun.reflect.misc.ConstructorUtil;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
import sun.reflect.misc.ReflectUtil;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
/**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
 * A utility class for reflectively finding methods, constuctors and fields
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
 * using reflection.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
class ReflectionUtils {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
    private static Reference methodCacheRef;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
    public static Class typeToClass(Class type) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
        return type.isPrimitive() ? ObjectHandler.typeNameToClass(type.getName()) : type;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
    public static boolean isPrimitive(Class type) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
        return primitiveTypeFor(type) != null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
    public static Class primitiveTypeFor(Class wrapper) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
        if (wrapper == Boolean.class) return Boolean.TYPE;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
        if (wrapper == Byte.class) return Byte.TYPE;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
        if (wrapper == Character.class) return Character.TYPE;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
        if (wrapper == Short.class) return Short.TYPE;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
        if (wrapper == Integer.class) return Integer.TYPE;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
        if (wrapper == Long.class) return Long.TYPE;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
        if (wrapper == Float.class) return Float.TYPE;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
        if (wrapper == Double.class) return Double.TYPE;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
        if (wrapper == Void.class) return Void.TYPE;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
        return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
     * Tests each element on the class arrays for assignability.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
     * @param argClasses arguments to be tested
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
     * @param argTypes arguments from Method
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
     * @return true if each class in argTypes is assignable from the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
     *         corresponding class in argClasses.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
    private static boolean matchArguments(Class[] argClasses, Class[] argTypes) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
        return matchArguments(argClasses, argTypes, false);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
     * Tests each element on the class arrays for equality.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
     * @param argClasses arguments to be tested
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
     * @param argTypes arguments from Method
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
     * @return true if each class in argTypes is equal to the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
     *         corresponding class in argClasses.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
    private static boolean matchExplicitArguments(Class[] argClasses, Class[] argTypes) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
        return matchArguments(argClasses, argTypes, true);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
    private static boolean matchArguments(Class[] argClasses,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
                                          Class[] argTypes, boolean explicit) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
        boolean match = (argClasses.length == argTypes.length);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
        for(int j = 0; j < argClasses.length && match; j++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
            Class argType = argTypes[j];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
            if (argType.isPrimitive()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
                argType = typeToClass(argType);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
            if (explicit) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
                // Test each element for equality
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
                if (argClasses[j] != argType) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
                    match = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
                // Consider null an instance of all classes.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
                if (argClasses[j] != null &&
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
                    !(argType.isAssignableFrom(argClasses[j]))) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
                    match = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
        return match;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
     * @return the method which best matches the signature or throw an exception
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
     *         if it can't be found or the method is ambiguous.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
    static Method getPublicMethod(Class declaringClass, String methodName,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
                                           Class[] argClasses) throws NoSuchMethodException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
        Method m;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
        m = findPublicMethod(declaringClass, methodName, argClasses);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
        if (m == null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
            throw new NoSuchMethodException(declaringClass.getName() + "." + methodName);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
        return m;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
     * @return the method which best matches the signature or null if it cant be found or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
     *         the method is ambiguous.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
    public static Method findPublicMethod(Class declaringClass, String methodName,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
                                           Class[] argClasses) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
        // Many methods are "getters" which take no arguments.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
        // This permits the following optimisation which
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
        // avoids the expensive call to getMethods().
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
        if (argClasses.length == 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
                return MethodUtil.getMethod(declaringClass, methodName, argClasses);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
            catch (NoSuchMethodException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
                  return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
            } catch (SecurityException se) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
                // fall through
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
        Method[] methods = MethodUtil.getPublicMethods(declaringClass);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
        List list = new ArrayList();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
        for(int i = 0; i < methods.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
            // Collect all the methods which match the signature.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
            Method method = methods[i];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
            if (method.getName().equals(methodName)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
                if (matchArguments(argClasses, method.getParameterTypes())) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
                    list.add(method);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   161
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
        if (list.size() > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
            if (list.size() == 1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
                return (Method)list.get(0);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
            else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   169
                ListIterator iterator = list.listIterator();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   170
                Method method;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
                while (iterator.hasNext()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   172
                    method = (Method)iterator.next();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   173
                    if (matchExplicitArguments(argClasses, method.getParameterTypes())) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   174
                        return method;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   175
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   176
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   177
                // There are more than one method which matches this signature.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   178
                // try to return the most specific method.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   179
                return getMostSpecificMethod(list, argClasses);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   180
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   181
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
        return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   183
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   184
90ce3da70b43 Initial load
duke
parents:
diff changeset
   185
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   186
     * Return the most specific method from the list of methods which
90ce3da70b43 Initial load
duke
parents:
diff changeset
   187
     * matches the args. The most specific method will have the most
90ce3da70b43 Initial load
duke
parents:
diff changeset
   188
     * number of equal parameters or will be closest in the inheritance
90ce3da70b43 Initial load
duke
parents:
diff changeset
   189
     * heirarchy to the runtime execution arguments.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   190
     * <p>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   191
     * See the JLS section 15.12
90ce3da70b43 Initial load
duke
parents:
diff changeset
   192
     * http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#20448
90ce3da70b43 Initial load
duke
parents:
diff changeset
   193
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   194
     * @param methods List of methods which already have the same param length
90ce3da70b43 Initial load
duke
parents:
diff changeset
   195
     *                and arg types are assignable to param types
90ce3da70b43 Initial load
duke
parents:
diff changeset
   196
     * @param args an array of param types to match
90ce3da70b43 Initial load
duke
parents:
diff changeset
   197
     * @return method or null if a specific method cannot be determined
90ce3da70b43 Initial load
duke
parents:
diff changeset
   198
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   199
    private static Method getMostSpecificMethod(List methods, Class[] args) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   200
        Method method = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   201
90ce3da70b43 Initial load
duke
parents:
diff changeset
   202
        int matches = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   203
        int lastMatch = matches;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   204
90ce3da70b43 Initial load
duke
parents:
diff changeset
   205
        ListIterator iterator = methods.listIterator();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   206
        while (iterator.hasNext()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   207
            Method m = (Method)iterator.next();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   208
            Class[] mArgs = m.getParameterTypes();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   209
            matches = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   210
            for (int i = 0; i < args.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   211
                Class mArg = mArgs[i];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   212
                if (mArg.isPrimitive()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   213
                    mArg = typeToClass(mArg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   214
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   215
                if (args[i] == mArg) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   216
                    matches++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   217
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   218
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   219
            if (matches == 0 && lastMatch == 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   220
                if (method == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   221
                    method = m;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   222
                } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   223
                    // Test existing method. We already know that the args can
90ce3da70b43 Initial load
duke
parents:
diff changeset
   224
                    // be assigned to all the method params. However, if the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   225
                    // current method parameters is higher in the inheritance
90ce3da70b43 Initial load
duke
parents:
diff changeset
   226
                    // hierarchy then replace it.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   227
                    if (!matchArguments(method.getParameterTypes(),
90ce3da70b43 Initial load
duke
parents:
diff changeset
   228
                                        m.getParameterTypes())) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   229
                        method = m;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   230
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   231
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   232
            } else if (matches > lastMatch) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   233
                lastMatch = matches;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   234
                method = m;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   235
            } else if (matches == lastMatch) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   236
                // ambiguous method selection.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   237
                method = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   238
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   239
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   240
        return method;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   241
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   242
90ce3da70b43 Initial load
duke
parents:
diff changeset
   243
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   244
     * @return the method or null if it can't be found or is ambiguous.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   245
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   246
    public static Method findMethod(Class targetClass, String methodName,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   247
                                    Class[] argClasses) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   248
        Method m = findPublicMethod(targetClass, methodName, argClasses);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   249
        if (m != null && Modifier.isPublic(m.getDeclaringClass().getModifiers())) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   250
            return m;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   251
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   252
90ce3da70b43 Initial load
duke
parents:
diff changeset
   253
        /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   254
        Search the interfaces for a public version of this method.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   255
90ce3da70b43 Initial load
duke
parents:
diff changeset
   256
        Example: the getKeymap() method of a JTextField
90ce3da70b43 Initial load
duke
parents:
diff changeset
   257
        returns a package private implementation of the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   258
        of the public Keymap interface. In the Keymap
90ce3da70b43 Initial load
duke
parents:
diff changeset
   259
        interface there are a number of "properties" one
90ce3da70b43 Initial load
duke
parents:
diff changeset
   260
        being the "resolveParent" property implied by the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   261
        getResolveParent() method. This getResolveParent()
90ce3da70b43 Initial load
duke
parents:
diff changeset
   262
        cannot be called reflectively because the class
90ce3da70b43 Initial load
duke
parents:
diff changeset
   263
        itself is not public. Instead we search the class's
90ce3da70b43 Initial load
duke
parents:
diff changeset
   264
        interfaces and find the getResolveParent()
90ce3da70b43 Initial load
duke
parents:
diff changeset
   265
        method of the Keymap interface - on which invoke
90ce3da70b43 Initial load
duke
parents:
diff changeset
   266
        may be applied without error.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   267
90ce3da70b43 Initial load
duke
parents:
diff changeset
   268
        So in :-
90ce3da70b43 Initial load
duke
parents:
diff changeset
   269
90ce3da70b43 Initial load
duke
parents:
diff changeset
   270
            JTextField o = new JTextField("Hello, world");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   271
            Keymap km = o.getKeymap();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   272
            Method m1 = km.getClass().getMethod("getResolveParent", new Class[0]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   273
            Method m2 = Keymap.class.getMethod("getResolveParent", new Class[0]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   274
90ce3da70b43 Initial load
duke
parents:
diff changeset
   275
        Methods m1 and m2 are different. The invocation of method
90ce3da70b43 Initial load
duke
parents:
diff changeset
   276
        m1 unconditionally throws an IllegalAccessException where
90ce3da70b43 Initial load
duke
parents:
diff changeset
   277
        the invocation of m2 will invoke the implementation of the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   278
        method. Note that (ignoring the overloading of arguments)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   279
        there is only one implementation of the named method which
90ce3da70b43 Initial load
duke
parents:
diff changeset
   280
        may be applied to this target.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   281
        */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   282
        for(Class type = targetClass; type != null; type = type.getSuperclass()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   283
            Class[] interfaces = type.getInterfaces();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   284
            for(int i = 0; i < interfaces.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   285
                m = findPublicMethod(interfaces[i], methodName, argClasses);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   286
                if (m != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   287
                    return m;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   288
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   289
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   290
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   291
        return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   292
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   293
90ce3da70b43 Initial load
duke
parents:
diff changeset
   294
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   295
     * A class that represents the unique elements of a method that will be a
90ce3da70b43 Initial load
duke
parents:
diff changeset
   296
     * key in the method cache.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   297
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   298
    private static class Signature {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   299
        private Class targetClass;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   300
        private String methodName;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   301
        private Class[] argClasses;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   302
90ce3da70b43 Initial load
duke
parents:
diff changeset
   303
        private volatile int hashCode = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   304
90ce3da70b43 Initial load
duke
parents:
diff changeset
   305
        public Signature(Class targetClass, String methodName, Class[] argClasses) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   306
            this.targetClass = targetClass;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   307
            this.methodName = methodName;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   308
            this.argClasses = argClasses;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   309
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   310
90ce3da70b43 Initial load
duke
parents:
diff changeset
   311
        public boolean equals(Object o2) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   312
            if (this == o2) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   313
                return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   314
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   315
            Signature that = (Signature)o2;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   316
            if (!(targetClass == that.targetClass)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   317
                return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   318
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   319
            if (!(methodName.equals(that.methodName))) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   320
                return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   321
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   322
            if (argClasses.length != that.argClasses.length) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   323
                return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   324
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   325
            for (int i = 0; i < argClasses.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   326
                if (!(argClasses[i] == that.argClasses[i])) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   327
                  return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   328
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   329
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   330
            return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   331
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   332
90ce3da70b43 Initial load
duke
parents:
diff changeset
   333
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   334
         * Hash code computed using algorithm suggested in
90ce3da70b43 Initial load
duke
parents:
diff changeset
   335
         * Effective Java, Item 8.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   336
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   337
        public int hashCode() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   338
            if (hashCode == 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   339
                int result = 17;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   340
                result = 37 * result + targetClass.hashCode();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   341
                result = 37 * result + methodName.hashCode();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   342
                if (argClasses != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   343
                    for (int i = 0; i < argClasses.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   344
                        result = 37 * result + ((argClasses[i] == null) ? 0 :
90ce3da70b43 Initial load
duke
parents:
diff changeset
   345
                            argClasses[i].hashCode());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   346
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   347
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   348
                hashCode = result;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   349
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   350
            return hashCode;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   351
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   352
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   353
90ce3da70b43 Initial load
duke
parents:
diff changeset
   354
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   355
     * A wrapper to findMethod(), which will search or populate the method
90ce3da70b43 Initial load
duke
parents:
diff changeset
   356
     * in a cache.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   357
     * @throws exception if the method is ambiguios.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   358
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   359
    public static synchronized Method getMethod(Class targetClass,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   360
                                                String methodName,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   361
                                                Class[] argClasses) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   362
        Object signature = new Signature(targetClass, methodName, argClasses);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   363
90ce3da70b43 Initial load
duke
parents:
diff changeset
   364
        Method method = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   365
        Map methodCache = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   366
        boolean cache = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   367
        if (ReflectUtil.isPackageAccessible(targetClass)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   368
            cache = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   369
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   370
90ce3da70b43 Initial load
duke
parents:
diff changeset
   371
        if (cache && methodCacheRef != null &&
90ce3da70b43 Initial load
duke
parents:
diff changeset
   372
            (methodCache = (Map)methodCacheRef.get()) != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   373
            method = (Method)methodCache.get(signature);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   374
            if (method != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   375
                return method;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   376
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   377
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   378
        method = findMethod(targetClass, methodName, argClasses);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   379
        if (cache && method != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   380
            if (methodCache == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   381
                methodCache = new HashMap();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   382
                methodCacheRef = new SoftReference(methodCache);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   383
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   384
            methodCache.put(signature, method);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   385
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   386
        return method;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   387
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   388
90ce3da70b43 Initial load
duke
parents:
diff changeset
   389
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   390
     * Return a constructor on the class with the arguments.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   391
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   392
     * @throws exception if the method is ambiguios.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   393
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   394
    public static Constructor getConstructor(Class cls, Class[] args) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   395
        Constructor constructor = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   396
90ce3da70b43 Initial load
duke
parents:
diff changeset
   397
        // PENDING: Implement the resolutuion of ambiguities properly.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   398
        Constructor[] ctors = ConstructorUtil.getConstructors(cls);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   399
        for(int i = 0; i < ctors.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   400
            if (matchArguments(args, ctors[i].getParameterTypes())) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   401
                constructor = ctors[i];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   402
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   403
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   404
        return constructor;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   405
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   406
90ce3da70b43 Initial load
duke
parents:
diff changeset
   407
    public static Object getPrivateField(Object instance, Class cls, String name) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   408
        return getPrivateField(instance, cls, name, null);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   409
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   410
90ce3da70b43 Initial load
duke
parents:
diff changeset
   411
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   412
     * Returns the value of a private field.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   413
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   414
     * @param instance object instance
90ce3da70b43 Initial load
duke
parents:
diff changeset
   415
     * @param cls class
90ce3da70b43 Initial load
duke
parents:
diff changeset
   416
     * @param name name of the field
90ce3da70b43 Initial load
duke
parents:
diff changeset
   417
     * @param el an exception listener to handle exceptions; or null
90ce3da70b43 Initial load
duke
parents:
diff changeset
   418
     * @return value of the field; null if not found or an error is encountered
90ce3da70b43 Initial load
duke
parents:
diff changeset
   419
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   420
    public static Object getPrivateField(Object instance, Class cls,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   421
                                         String name, ExceptionListener el) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   422
        try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   423
            Field f = cls.getDeclaredField(name);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   424
            f.setAccessible(true);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   425
            return f.get(instance);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   426
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   427
        catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   428
            if (el != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   429
                el.exceptionThrown(e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   430
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   431
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   432
        return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   433
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   434
}