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 }