View Javadoc

1   package org.apache.velocity.util.introspection;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.    
20   */
21  
22  /**
23   *
24   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
25   * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
26   * @author <a href="mailto:Christoph.Reck@dlr.de">Christoph Reck</a>
27   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
28   * @author <a href="mailto:szegedia@freemail.hu">Attila Szegedi</a>
29   * @author Nathan Bubna
30   * @version $Id: IntrospectionUtils.java 476785 2006-11-19 10:06:21Z henning $
31   * @since 1.6
32   */
33  public class IntrospectionUtils
34  {
35  
36      /**
37       * Determines whether a type represented by a class object is
38       * convertible to another type represented by a class object using a
39       * method invocation conversion, treating object types of primitive
40       * types as if they were primitive types (that is, a Boolean actual
41       * parameter type matches boolean primitive formal type). This behavior
42       * is because this method is used to determine applicable methods for
43       * an actual parameter list, and primitive types are represented by
44       * their object duals in reflective method calls.
45       *
46       * @param formal the formal parameter type to which the actual
47       * parameter type should be convertible
48       * @param actual the actual parameter type.
49       * @param possibleVarArg whether or not we're dealing with the last parameter
50       * in the method declaration
51       * @return true if either formal type is assignable from actual type,
52       * or formal is a primitive type and actual is its corresponding object
53       * type or an object type of a primitive type that can be converted to
54       * the formal type.
55       */
56      public static boolean isMethodInvocationConvertible(Class formal,
57                                                          Class actual,
58                                                          boolean possibleVarArg)
59      {
60          /* if it's a null, it means the arg was null */
61          if (actual == null && !formal.isPrimitive())
62          {
63              return true;
64          }
65  
66          /* Check for identity or widening reference conversion */
67          if (actual != null && formal.isAssignableFrom(actual))
68          {
69              return true;
70          }
71  
72          /* Check for boxing with widening primitive conversion. Note that
73           * actual parameters are never primitives. */
74          if (formal.isPrimitive())
75          {
76              if(formal == Boolean.TYPE && actual == Boolean.class)
77                  return true;
78              if(formal == Character.TYPE && actual == Character.class)
79                  return true;
80              if(formal == Byte.TYPE && actual == Byte.class)
81                  return true;
82              if(formal == Short.TYPE &&
83                 (actual == Short.class || actual == Byte.class))
84                  return true;
85              if(formal == Integer.TYPE &&
86                 (actual == Integer.class || actual == Short.class ||
87                  actual == Byte.class))
88                  return true;
89              if(formal == Long.TYPE &&
90                 (actual == Long.class || actual == Integer.class ||
91                  actual == Short.class || actual == Byte.class))
92                  return true;
93              if(formal == Float.TYPE &&
94                 (actual == Float.class || actual == Long.class ||
95                  actual == Integer.class || actual == Short.class ||
96                  actual == Byte.class))
97                  return true;
98              if(formal == Double.TYPE &&
99                 (actual == Double.class || actual == Float.class ||
100                 actual == Long.class || actual == Integer.class ||
101                 actual == Short.class || actual == Byte.class))
102                 return true;
103         }
104 
105         /* Check for vararg conversion. */
106         if (possibleVarArg && formal.isArray())
107         {
108             if (actual.isArray())
109             {
110                 actual = actual.getComponentType();
111             }
112             return isMethodInvocationConvertible(formal.getComponentType(),
113                                                  actual, false);
114         }
115         return false;
116     }
117 
118     /**
119      * Determines whether a type represented by a class object is
120      * convertible to another type represented by a class object using a
121      * method invocation conversion, without matching object and primitive
122      * types. This method is used to determine the more specific type when
123      * comparing signatures of methods.
124      *
125      * @param formal the formal parameter type to which the actual
126      * parameter type should be convertible
127      * @param actual the actual parameter type.
128      * @param possibleVarArg whether or not we're dealing with the last parameter
129      * in the method declaration
130      * @return true if either formal type is assignable from actual type,
131      * or formal and actual are both primitive types and actual can be
132      * subject to widening conversion to formal.
133      */
134     public static boolean isStrictMethodInvocationConvertible(Class formal,
135                                                               Class actual,
136                                                               boolean possibleVarArg)
137     {
138         /* we shouldn't get a null into, but if so */
139         if (actual == null && !formal.isPrimitive())
140         {
141             return true;
142         }
143 
144         /* Check for identity or widening reference conversion */
145         if(formal.isAssignableFrom(actual))
146         {
147             return true;
148         }
149 
150         /* Check for widening primitive conversion. */
151         if(formal.isPrimitive())
152         {
153             if(formal == Short.TYPE && (actual == Byte.TYPE))
154                 return true;
155             if(formal == Integer.TYPE &&
156                (actual == Short.TYPE || actual == Byte.TYPE))
157                 return true;
158             if(formal == Long.TYPE &&
159                (actual == Integer.TYPE || actual == Short.TYPE ||
160                 actual == Byte.TYPE))
161                 return true;
162             if(formal == Float.TYPE &&
163                (actual == Long.TYPE || actual == Integer.TYPE ||
164                 actual == Short.TYPE || actual == Byte.TYPE))
165                 return true;
166             if(formal == Double.TYPE &&
167                (actual == Float.TYPE || actual == Long.TYPE ||
168                 actual == Integer.TYPE || actual == Short.TYPE ||
169                 actual == Byte.TYPE))
170                 return true;
171         }
172 
173         /* Check for vararg conversion. */
174         if (possibleVarArg && formal.isArray())
175         {
176             if (actual.isArray())
177             {
178                 actual = actual.getComponentType();
179             }
180             return isStrictMethodInvocationConvertible(formal.getComponentType(),
181                                                        actual, false);
182         }
183         return false;
184     }
185 }