1 package com.fasterxml.classmate;
2
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.Field;
5 import java.lang.reflect.Method;
6 import java.lang.reflect.Modifier;
7 import java.lang.reflect.Type;
8 import java.util.*;
9
10 import com.fasterxml.classmate.members.*;
11
12 public abstract class ResolvedType
13 implements Type
14 {
15 public final static ResolvedType[] NO_TYPES = new ResolvedType[0];
16
17 protected final static RawConstructor[] NO_CONSTRUCTORS = new RawConstructor[0];
18 protected final static RawField[] NO_FIELDS = new RawField[0];
19 protected final static RawMethod[] NO_METHODS = new RawMethod[0];
20
21 protected final Class<?> _erasedType;
22
23 /**
24 * Type bindings active when resolving members (methods, fields,
25 * constructors) of this type
26 */
27 protected final TypeBindings _typeBindings;
28
29 /*
30 /**********************************************************************
31 /* Life cycle
32 /**********************************************************************
33 */
34
35 protected ResolvedType(Class<?> cls, TypeBindings bindings)
36 {
37 _erasedType = cls;
38 _typeBindings = (bindings == null) ? TypeBindings.emptyBindings() : bindings;
39 }
40
41 /**
42 * Method that can be used to check if call to {@link TypeResolver#resolveSubtype(ResolvedType, Class)}
43 * may ever succeed; if false, it will fail with an exception, if true, it may succeed.
44 */
45 public abstract boolean canCreateSubtypes();
46
47 /**
48 * Method that can be used to check if call to {@link TypeResolver#resolveSubtype(ResolvedType, Class)}
49 * will succeed for specific type; if false, it will fail with an exception; if tru it
50 * will succeed.
51 */
52 public final boolean canCreateSubtype(Class<?> subtype) {
53 return canCreateSubtypes() && _erasedType.isAssignableFrom(subtype);
54 }
55
56 /*
57 /**********************************************************************
58 /* Accessors for related types
59 /**********************************************************************
60 */
61
62 /**
63 * Returns type-erased Class<?> that this resolved type has.
64 */
65 public Class<?> getErasedType() { return _erasedType; }
66
67 /**
68 * Returns parent class of this type, if it has one; primitive types
69 * and interfaces have no parent class, nor does Object type
70 * {@link java.lang.Object}.
71 * Also, placeholders for cyclic (recursive) types return null for
72 * this method.
73 */
74 public abstract ResolvedType getParentClass();
75
76 /**
77 * Accessor that must be used to find out actual type in
78 * case of "self-reference"; case where type refers
79 * recursive to itself (like, <code>T implements Comparable<T></code>).
80 * For all other types returns null but for self-references "real" type.
81 * Separate accessor is provided to avoid accidental infinite loops.
82 */
83 public abstract ResolvedType getSelfReferencedType();
84
85 /**
86 * Method that can be used to access element type of array types; will return
87 * null for non-array types, and non-null type for array types.
88 */
89 public abstract ResolvedType getArrayElementType();
90
91 /**
92 * Returns ordered list of interfaces (in declaration order) that this type
93 * implements.
94 *
95 * @return List of interfaces this type implements, if any; empty list if none
96 */
97 public abstract List<ResolvedType> getImplementedInterfaces();
98
99 /**
100 * Returns list of generic type declarations for this type, in order they
101 * are declared in class description.
102 */
103 public List<ResolvedType> getTypeParameters() {
104 return _typeBindings.getTypeParameters();
105 }
106
107 /**
108 * Method for accessing bindings of type variables to resolved types in context
109 * of this type. It has same number of entries as return List of
110 * {@link #getTypeParameters}, accessible using declared name to which they
111 * bind; for example, {@link java.util.Map} has 2 type bindings; one for
112 * key type (name "K", from Map.java) and one for value type
113 * (name "V", from Map.java).
114 */
115 public TypeBindings getTypeBindings() { return _typeBindings; }
116
117 /**
118 * Method that will try to find type parameterization this type
119 * has for specified super type
120 *
121 * @return List of type parameters for specified supertype (which may
122 * be empty, if supertype is not a parametric type); null if specified
123 * type is not a super type of this type
124 */
125 public List<ResolvedType> typeParametersFor(Class<?> erasedSupertype)
126 {
127 ResolvedType type = findSupertype(erasedSupertype);
128 if (type != null) {
129 return type.getTypeParameters();
130 }
131 // nope; doesn't look like we extend or implement super type in question
132 return null;
133 }
134
135 /**
136 * Method for finding super type of this type that has specified type
137 * erased signature. If supertype is an interface which is implemented
138 * using multiple inheritance paths, preference is given to interfaces
139 * implemented "highest up the stack" (directly implemented interfaces
140 * over interfaces superclass implements).
141 */
142 public ResolvedType findSupertype(Class<?> erasedSupertype)
143 {
144 if (erasedSupertype == _erasedType) {
145 return this;
146 }
147 // Check super interfaces first:
148 if (erasedSupertype.isInterface()) {
149 for (ResolvedType it : getImplementedInterfaces()) {
150 ResolvedType type = it.findSupertype(erasedSupertype);
151 if (type != null) {
152 return type;
153 }
154 }
155 }
156 // and if not found, super class and its supertypes
157 ResolvedType pc = getParentClass();
158 if (pc != null) {
159 ResolvedType type = pc.findSupertype(erasedSupertype);
160 if (type != null) {
161 return type;
162 }
163 }
164 // nope; doesn't look like we extend or implement super type in question
165 return null;
166 }
167
168 /*
169 /**********************************************************************
170 /* Accessors for simple properties
171 /**********************************************************************
172 */
173
174 public abstract boolean isInterface();
175 public final boolean isConcrete() { return !isAbstract(); }
176 public abstract boolean isAbstract();
177
178 /**
179 * Method that indicates whether this type is an array type.
180 */
181 public abstract boolean isArray();
182
183 /**
184 * Method that indicates whether this type is one of small number of primitive
185 * Java types; not including array types of primitive types but just basic
186 * primitive types.
187 */
188 public abstract boolean isPrimitive();
189
190 public final boolean isInstanceOf(Class<?> type) {
191 return type.isAssignableFrom(_erasedType);
192 }
193
194 /*
195 /**********************************************************************
196 /* Accessors for raw (minimally procesed) members
197 /**********************************************************************
198 */
199
200 public List<RawConstructor> getConstructors() { return Collections.emptyList(); }
201 public List<RawField> getMemberFields() { return Collections.emptyList(); }
202 public List<RawMethod> getMemberMethods() { return Collections.emptyList(); }
203 public List<RawField> getStaticFields() { return Collections.emptyList(); }
204 public List<RawMethod> getStaticMethods() { return Collections.emptyList(); }
205
206 /*
207 /**********************************************************************
208 /* String representations
209 /**********************************************************************
210 */
211
212 /**
213 * Method that returns full generic signature of the type; suitable
214 * as signature for things like ASM package.
215 */
216 public String getSignature() {
217 StringBuilder sb = new StringBuilder();
218 return appendSignature(sb).toString();
219 }
220
221 /**
222 * Method that returns type erased signature of the type; suitable
223 * as non-generic signature some packages need
224 */
225 public String getErasedSignature() {
226 StringBuilder sb = new StringBuilder();
227 return appendErasedSignature(sb).toString();
228 }
229
230 /**
231 * Human-readable full description of type, which includes specification
232 * of super types (in brief format)
233 */
234 public String getFullDescription() {
235 StringBuilder sb = new StringBuilder();
236 return appendFullDescription(sb).toString();
237 }
238
239 /**
240 * Human-readable brief description of type, which does not include
241 * information about super types.
242 */
243 public String getBriefDescription() {
244 StringBuilder sb = new StringBuilder();
245 return appendBriefDescription(sb).toString();
246 }
247
248 public abstract StringBuilder appendBriefDescription(StringBuilder sb);
249 public abstract StringBuilder appendFullDescription(StringBuilder sb);
250 public abstract StringBuilder appendSignature(StringBuilder sb);
251 public abstract StringBuilder appendErasedSignature(StringBuilder sb);
252
253 /*
254 /**********************************************************************
255 /* Standard methods
256 /**********************************************************************
257 */
258
259 @Override public String toString() {
260 return getBriefDescription();
261 }
262
263 @Override public int hashCode() {
264 return _erasedType.getName().hashCode() + _typeBindings.hashCode();
265 }
266
267 @Override public boolean equals(Object o)
268 {
269 if (o == this) return true;
270 // sub-types must be same:
271 if (o == null || o.getClass() != getClass()) return false;
272 // Should be possible to actually implement here...
273 ResolvedType other = (ResolvedType) o;
274 if (other._erasedType != _erasedType) {
275 return false;
276 }
277 // and type bindings must match as well
278 return _typeBindings.equals(other._typeBindings);
279 }
280
281 /*
282 /**********************************************************************
283 /* Helper methods for sub-classes; string construction
284 /**********************************************************************
285 */
286
287 protected StringBuilder _appendClassSignature(StringBuilder sb)
288 {
289 sb.append('L');
290 sb = _appendClassName(sb);
291 int count = _typeBindings.size();
292 if (count > 0) {
293 sb.append('<');
294 for (int i = 0; i < count; ++i) {
295 sb = _typeBindings.getBoundType(i).appendErasedSignature(sb);
296 }
297 sb.append('>');
298 }
299 sb.append(';');
300 return sb;
301 }
302
303 protected StringBuilder _appendErasedClassSignature(StringBuilder sb)
304 {
305 sb.append('L');
306 sb = _appendClassName(sb);
307 sb.append(';');
308 return sb;
309 }
310
311 protected StringBuilder _appendClassDescription(StringBuilder sb)
312 {
313 sb.append(_erasedType.getName());
314 int count = _typeBindings.size();
315 if (count > 0) {
316 sb.append('<');
317 for (int i = 0; i < count; ++i) {
318 if (i > 0) {
319 sb.append(',');
320 }
321 sb = _typeBindings.getBoundType(i).appendBriefDescription(sb);
322 }
323 sb.append('>');
324 }
325 return sb;
326 }
327
328 protected StringBuilder _appendClassName(StringBuilder sb)
329 {
330 String name = _erasedType.getName();
331 for (int i = 0, len = name.length(); i < len; ++i) {
332 char c = name.charAt(i);
333 if (c == '.') c = '/';
334 sb.append(c);
335 }
336 return sb;
337 }
338
339 /*
340 /**********************************************************************
341 /* Helper methods for sub-classes; gathering members
342 /**********************************************************************
343 */
344
345 /**
346 * @param statics Whether to return static methods (true) or member methods (false)
347 */
348 protected RawField[] _getFields(boolean statics)
349 {
350 ArrayList<RawField> fields = new ArrayList<RawField>();
351 for (Field f : _erasedType.getDeclaredFields()) {
352 // Only skip synthetic fields, which should not really be exposed
353 if (!f.isSynthetic()) {
354 if (Modifier.isStatic(f.getModifiers()) == statics) {
355 fields.add(new RawField(this, f));
356 }
357 }
358 }
359 if (fields.isEmpty()) {
360 return NO_FIELDS;
361 }
362 return fields.toArray(new RawField[0]);
363 }
364
365 /**
366 * @param statics Whether to return static methods (true) or member methods (false)
367 */
368 protected RawMethod[] _getMethods(boolean statics)
369 {
370 ArrayList<RawMethod> methods = new ArrayList<RawMethod>();
371 for (Method m : _erasedType.getDeclaredMethods()) {
372 // Only skip synthetic fields, which should not really be exposed
373 if (!m.isSynthetic()) {
374 if (Modifier.isStatic(m.getModifiers()) == statics) {
375 methods.add(new RawMethod(this, m));
376 }
377 }
378 }
379 if (methods.isEmpty()) {
380 return NO_METHODS;
381 }
382 return methods.toArray(new RawMethod[0]);
383 }
384
385 protected RawConstructor[] _getConstructors()
386 {
387 ArrayList<RawConstructor> ctors = new ArrayList<RawConstructor>();
388 for (Constructor<?> c : _erasedType.getDeclaredConstructors()) {
389 // Only skip synthetic fields, which should not really be exposed
390 if (!c.isSynthetic()) {
391 ctors.add(new RawConstructor(this, c));
392 }
393 }
394 if (ctors.isEmpty()) {
395 return NO_CONSTRUCTORS;
396 }
397 return ctors.toArray(new RawConstructor[0]);
398 }
399 }
400