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 }