View Javadoc

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