Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: gnu/java/beans/decoder/MethodFinder.java


1   /* gnu.java.beans.decoder.MethodFinder
2      Copyright (C) 2004 Free Software Foundation, Inc.
3   
4   This file is part of GNU Classpath.
5   
6   GNU Classpath is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10   
11  GNU Classpath is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  General Public License for more details.
15  
16  You should have received a copy of the GNU General Public License
17  along with GNU Classpath; see the file COPYING.  If not, write to the
18  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  02110-1301 USA.
20  
21  Linking this library statically or dynamically with other modules is
22  making a combined work based on this library.  Thus, the terms and
23  conditions of the GNU General Public License cover the whole
24  combination.
25  
26  As a special exception, the copyright holders of this library give you
27  permission to link this library with independent modules to produce an
28  executable, regardless of the license terms of these independent
29  modules, and to copy and distribute the resulting executable under
30  terms of your choice, provided that you also meet, for each linked
31  independent module, the terms and conditions of the license of that
32  module.  An independent module is a module which is not derived from
33  or based on this library.  If you modify this library, you may extend
34  this exception to your version of the library, but you are not
35  obligated to do so.  If you do not wish to do so, delete this
36  exception statement from your version. */
37  
38  package gnu.java.beans.decoder;
39  
40  import java.lang.reflect.Constructor;
41  import java.lang.reflect.Method;
42  import java.util.HashMap;
43  
44  class MethodFinder
45  {
46    /** Provides a mapping between a wrapper class and its corresponding primitive's type. */
47    private static HashMap typeMapping = new HashMap();
48  
49    static {
50      typeMapping.put(Byte.class, Byte.TYPE);
51      typeMapping.put(Short.class, Short.TYPE);
52      typeMapping.put(Integer.class, Integer.TYPE);
53      typeMapping.put(Long.class, Long.TYPE);
54      typeMapping.put(Float.class, Float.TYPE);
55      typeMapping.put(Double.class, Double.TYPE);
56  
57      typeMapping.put(Character.class, Character.TYPE);
58      typeMapping.put(Boolean.class, Boolean.TYPE);
59    }
60  
61    private MethodFinder()
62    {
63    }
64  
65    /** Searches a Method which can accept the given arguments.
66     *
67     * @param klass
68     * @param name
69     * @param arguments
70     * @return
71     * @throws NoSuchMethodException
72     */
73    static Method getMethod(Class klass, String name, Object[] arguments)
74      throws NoSuchMethodException
75    {
76      // prepares array containing the types of the arguments
77      Class[] argumentTypes = getArgumentTypes(arguments);
78  
79      Method[] methods = klass.getMethods();
80  
81      // iterates over all public methods
82      for (int i = 0; i < methods.length; i++)
83      {
84        if (methods[i].getName().equals(name))
85        {
86          if (matchingArgumentTypes(methods[i].getParameterTypes(),
87            argumentTypes))
88            return methods[i];
89        }
90      }
91  
92      throw new NoSuchMethodException(
93        "Could not find a matching method named "
94          + name
95          + "() in class "
96          + klass);
97    }
98  
99    static Constructor getConstructor(Class klass, Object[] arguments)
100     throws NoSuchMethodException
101   {
102     Class[] argumentTypes = getArgumentTypes(arguments);
103     Constructor[] constructors = klass.getConstructors();
104 
105     // iterates over all public methods
106     for (int i = 0; i < constructors.length; i++)
107     {
108       if (matchingArgumentTypes(constructors[i].getParameterTypes(),
109         argumentTypes))
110         return constructors[i];
111     }
112 
113     throw new NoSuchMethodException(
114       "Could not find a matching constructor in class " + klass);
115   }
116 
117   /** Transforms an array of argument objects into an array of argument types.
118    * For each argument being null the argument is null, too. An argument type
119    * being null means: Accepts everything (although this can be ambigous).
120    * 
121    * @param arguments
122    * @return
123    */
124   private static Class[] getArgumentTypes(Object[] arguments)
125   {
126     if (arguments == null)
127       return new Class[0];
128 
129     // prepares array containing the types of the arguments
130     Class[] argumentTypes = new Class[arguments.length];
131     for (int i = 0; i < arguments.length; i++)
132       argumentTypes[i] =
133         (arguments[i] == null) ? null : arguments[i].getClass();
134     return argumentTypes;
135   }
136 
137   /** Tests whether the argument types supplied to the method argument types
138    * are assignable. In addition to the assignment specifications this method
139    * handles the primitive's wrapper classes as if they were of their
140    * primitive type (e.g Boolean.class equals Boolean.TYPE).
141    * When a supplied argument type is null it is assumed that no argument
142    * object was supplied for it and the test for this particular parameter will
143    * pass.
144    *
145    * @param methodArgTypes
146    * @param suppliedArgTypes
147    * @return
148    */
149   private static boolean matchingArgumentTypes(
150     Class[] methodArgTypes,
151     Class[] suppliedArgTypes)
152   {
153     if (methodArgTypes.length != suppliedArgTypes.length)
154       return false;
155 
156     for (int i = 0; i < methodArgTypes.length; i++)
157     {
158       if (suppliedArgTypes[i] == null)
159       {
160         // by definition a non-existant argument type (null) can be converted to everything
161         continue;
162       }
163       else if (typeMapping.containsKey(suppliedArgTypes[i]))
164       {
165         Class primitiveType =
166           (Class) typeMapping.get(suppliedArgTypes[i]);
167         if (!(methodArgTypes[i].isAssignableFrom(suppliedArgTypes[i])
168           || methodArgTypes[i].isAssignableFrom(primitiveType)))
169           return false;
170       }
171       else if (!methodArgTypes[i].isAssignableFrom(suppliedArgTypes[i]))
172         return false;
173     }
174 
175     return true;
176   }
177 }