1 package net.florianschoppmann.java.reflect;
2
3 import net.florianschoppmann.java.type.AbstractTypes;
4 import net.florianschoppmann.java.type.IntersectionType;
5
6 import javax.annotation.Nullable;
7 import javax.lang.model.element.Element;
8 import javax.lang.model.element.Name;
9 import javax.lang.model.element.TypeElement;
10 import javax.lang.model.element.TypeParameterElement;
11 import javax.lang.model.type.ArrayType;
12 import javax.lang.model.type.DeclaredType;
13 import javax.lang.model.type.ExecutableType;
14 import javax.lang.model.type.NoType;
15 import javax.lang.model.type.NullType;
16 import javax.lang.model.type.PrimitiveType;
17 import javax.lang.model.type.TypeKind;
18 import javax.lang.model.type.TypeMirror;
19 import java.lang.reflect.GenericArrayType;
20 import java.lang.reflect.GenericDeclaration;
21 import java.lang.reflect.ParameterizedType;
22 import java.lang.reflect.Type;
23 import java.lang.reflect.TypeVariable;
24 import java.lang.reflect.WildcardType;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.LinkedHashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Objects;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public final class ReflectionTypes extends AbstractTypes {
54 private static final ReflectionTypes INSTANCE = new ReflectionTypes();
55
56 private final ImmutableList<PrimitiveTypeImpl> primitiveTypes;
57 private final ImmutableList<TypeElementImpl> boxedTypeDeclarations;
58 {
59 List<PrimitiveTypeImpl> newTypes = new ArrayList<>(TypeKind.values().length);
60 List<TypeElementImpl> newDeclarations = new ArrayList<>(TypeKind.values().length);
61
62 newTypes.addAll(Collections.<PrimitiveTypeImpl>nCopies(TypeKind.values().length, null));
63 newDeclarations.addAll(Collections.<TypeElementImpl>nCopies(TypeKind.values().length, null));
64
65 addPrimitive(newTypes, newDeclarations, TypeKind.DOUBLE, PrimitiveTypeImpl.DOUBLE, Double.class);
66 addPrimitive(newTypes, newDeclarations, TypeKind.FLOAT, PrimitiveTypeImpl.FLOAT, Float.class);
67 addPrimitive(newTypes, newDeclarations, TypeKind.LONG, PrimitiveTypeImpl.LONG, Long.class);
68 addPrimitive(newTypes, newDeclarations, TypeKind.INT, PrimitiveTypeImpl.INT, Integer.class);
69 addPrimitive(newTypes, newDeclarations, TypeKind.SHORT, PrimitiveTypeImpl.SHORT, Short.class);
70 addPrimitive(newTypes, newDeclarations, TypeKind.BYTE, PrimitiveTypeImpl.BYTE, Byte.class);
71 addPrimitive(newTypes, newDeclarations, TypeKind.CHAR, PrimitiveTypeImpl.CHAR, Character.class);
72 addPrimitive(newTypes, newDeclarations, TypeKind.BOOLEAN, PrimitiveTypeImpl.BOOLEAN, Boolean.class);
73
74 primitiveTypes = ImmutableList.copyOf(newTypes);
75 boxedTypeDeclarations = ImmutableList.copyOf(newDeclarations);
76 }
77
78 private ReflectionTypes() { }
79
80
81
82
83
84
85
86
87 public static ReflectionTypes getInstance() {
88 return INSTANCE;
89 }
90
91 @Override
92 protected void requireValidElement(Element element) {
93 Objects.requireNonNull(element);
94 if (!(element instanceof ReflectionElement)) {
95 throw new IllegalArgumentException(String.format(
96 "Expected %s instance that was created by %s, but got instance of %s.",
97 Element.class.getSimpleName(), ReflectionTypes.class, element.getClass()
98 ));
99 }
100 }
101
102 @Override
103 protected void requireValidType(@Nullable TypeMirror type) {
104 if (!(type instanceof ReflectionTypeMirror) && type != null) {
105 throw new IllegalArgumentException(String.format(
106 "Expected %s instance that was created by %s, but got instance of %s.",
107 TypeMirror.class.getSimpleName(), ReflectionTypes.class, type.getClass()
108 ));
109 }
110 }
111
112 private void addPrimitive(List<PrimitiveTypeImpl> newPrimitiveTypes, List<TypeElementImpl> newBoxedTypeDeclarations,
113 TypeKind kind, PrimitiveTypeImpl primitiveType, Class<?> clazz) {
114 newPrimitiveTypes.set(kind.ordinal(), primitiveType);
115 newBoxedTypeDeclarations.set(kind.ordinal(), ((DeclaredTypeImpl) typeMirror(clazz)).asElement());
116 }
117
118 @Override
119 public TypeElement boxedClass(PrimitiveType primitiveType) {
120 requireValidType(Objects.requireNonNull(primitiveType));
121 @Nullable TypeElementImpl typeElement = boxedTypeDeclarations.get(primitiveType.getKind().ordinal());
122 assert typeElement != null : "Array with boxed type declarations incorrectly initialized.";
123 return typeElement;
124 }
125
126 @Override
127 public PrimitiveType unboxedType(TypeMirror type) {
128 requireValidType(Objects.requireNonNull(type));
129
130 if (type.getKind() != TypeKind.DECLARED) {
131 throw new IllegalArgumentException(String.format(
132 "Expected type mirror of kind %s, but got %s.", TypeKind.DECLARED, type
133 ));
134 }
135
136 Name name = ((DeclaredTypeImpl) type).asElement().getQualifiedName();
137 if (name.contentEquals(Double.class.getName())) {
138 return PrimitiveTypeImpl.DOUBLE;
139 } else if (name.contentEquals(Float.class.getName())) {
140 return PrimitiveTypeImpl.FLOAT;
141 } else if (name.contentEquals(Long.class.getName())) {
142 return PrimitiveTypeImpl.LONG;
143 } else if (name.contentEquals(Integer.class.getName())) {
144 return PrimitiveTypeImpl.INT;
145 } else if (name.contentEquals(Short.class.getName())) {
146 return PrimitiveTypeImpl.SHORT;
147 } else if (name.contentEquals(Byte.class.getName())) {
148 return PrimitiveTypeImpl.BYTE;
149 } else if (name.contentEquals(Character.class.getName())) {
150 return PrimitiveTypeImpl.CHAR;
151 } else if (name.contentEquals(Boolean.class.getName())) {
152 return PrimitiveTypeImpl.BOOLEAN;
153 } else {
154 throw new IllegalArgumentException(String.format("Expected boxed type, but got %s.", type));
155 }
156 }
157
158
159
160
161 private ReflectionTypeMirror mirrorClass(Class<?> clazz, MirrorContext mirrorContext) {
162 if (clazz.isArray()) {
163 return new ArrayTypeImpl(mirrorContext.mirror(clazz.getComponentType()));
164 } else if (clazz.isPrimitive()) {
165 return (ReflectionTypeMirror) getPrimitiveType(TypeKind.valueOf(clazz.getName().toUpperCase()));
166 } else {
167
168 @Nullable Class<?> enclosingClass = clazz.getEnclosingClass();
169 ReflectionTypeMirror enclosingType = enclosingClass == null
170 ? NoTypeImpl.NONE
171 : mirrorContext.mirror(enclosingClass);
172 return new DeclaredTypeImpl(enclosingType, mirrorContext.typeDeclaration(clazz),
173 Collections.<ReflectionTypeMirror>emptyList());
174 }
175 }
176
177
178
179
180 private static DeclaredTypeImpl mirrorParameterizedType(ParameterizedType parameterizedType,
181 MirrorContext mirrorContext) {
182 Class<?> rawClass = (Class<?>) parameterizedType.getRawType();
183 TypeElementImpl typeDeclaration = mirrorContext.typeDeclaration(rawClass);
184 @Nullable Type ownerType = parameterizedType.getOwnerType();
185 ReflectionTypeMirror ownerTypeMirror = ownerType == null
186 ? NoTypeImpl.NONE
187 : mirrorContext.mirror(ownerType);
188 return new DeclaredTypeImpl(ownerTypeMirror, typeDeclaration,
189 mirrorContext.mirror(parameterizedType.getActualTypeArguments()));
190 }
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205 private static WildcardTypeImpl mirrorWildcardType(WildcardType wildcardType, MirrorContext mirrorContext) {
206 Type[] upperBounds = wildcardType.getUpperBounds();
207 Type[] lowerBounds = wildcardType.getLowerBounds();
208
209
210 assert upperBounds.length == 1 && lowerBounds.length <= 1
211 && (lowerBounds.length == 0 || Object.class.equals(upperBounds[0]));
212
213 @Nullable ReflectionTypeMirror extendsBounds;
214 if (Object.class.equals(upperBounds[0])) {
215 extendsBounds = null;
216 } else {
217 extendsBounds = mirrorContext.mirror(upperBounds[0]);
218 }
219
220 @Nullable ReflectionTypeMirror superBound;
221 if (lowerBounds.length == 0) {
222 superBound = null;
223 } else {
224 superBound = mirrorContext.mirror(lowerBounds[0]);
225 }
226 return new WildcardTypeImpl(extendsBounds, superBound);
227 }
228
229 static void requireCondition(boolean condition, String formatString, Object argument) {
230 if (!condition) {
231 throw new IllegalStateException(String.format(formatString, argument));
232 }
233 }
234
235 private static TypeVariableImpl mirrorTypeVariable(TypeVariable<?> typeVariable, MirrorContext mirrorContext) {
236 GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
237 if (genericDeclaration instanceof Class<?>) {
238 TypeElementImpl typeDeclaration = mirrorContext.typeDeclaration((Class<?>) genericDeclaration);
239 @Nullable TypeParameterElementImpl element = null;
240 for (TypeParameterElementImpl typeParameter: typeDeclaration.getTypeParameters()) {
241 if (typeParameter.getSimpleName().contentEquals(typeVariable.getName())) {
242 element = typeParameter;
243 break;
244 }
245 }
246 requireCondition(element != null,
247 "Could not find the type-parameter element that corresponds to type variable %s.", typeVariable);
248 assert element != null : "redundant check for FindBugs";
249 return element.asType();
250 } else {
251 throw new UnsupportedOperationException("Method or constructor type parameters not supported.");
252 }
253 }
254
255 ReflectionTypeMirror mirrorInternal(Type type, MirrorContext mirrorContext) {
256 @Nullable ReflectionTypeMirror typeMirror = null;
257 if (type instanceof Class<?>) {
258 typeMirror = mirrorClass((Class<?>) type, mirrorContext);
259 } else if (type instanceof ParameterizedType) {
260 typeMirror = mirrorParameterizedType((ParameterizedType) type, mirrorContext);
261 } else if (type instanceof GenericArrayType) {
262 typeMirror = new ArrayTypeImpl(
263 mirrorContext.mirror(((GenericArrayType) type).getGenericComponentType())
264 );
265 } else if (type instanceof WildcardType) {
266 typeMirror = mirrorWildcardType((WildcardType) type, mirrorContext);
267 } else if (type instanceof TypeVariable<?>) {
268 typeMirror = mirrorTypeVariable((TypeVariable<?>) type, mirrorContext);
269 }
270 requireCondition(typeMirror != null,
271 "Expected Class, ParameterizedType, GenericArrayType, WildcardType, or TypeVariable instance, but got %s.",
272 type);
273 assert typeMirror != null : "redundant check for FindBugs";
274 return typeMirror;
275 }
276
277
278
279
280
281
282
283
284
285
286 public TypeElement typeElement(Class<?> clazz) {
287 if (clazz.isArray() || clazz.isPrimitive()) {
288 throw new IllegalArgumentException(String.format("Expected class or interface type, but got %s.", clazz));
289 }
290
291 return ((DeclaredTypeImpl) typeMirror(clazz)).asElement();
292 }
293
294
295
296
297
298
299
300
301
302
303
304
305
306 @Override
307 public TypeMirror typeMirror(Type type) {
308 Map<Class<?>, TypeElementImpl> typeDeclarations = new LinkedHashMap<>();
309 Map<Class<?>, TypeElementImpl> newTypeDeclarations = new LinkedHashMap<>();
310 MirrorContext mirrorContext = new MirrorContext(this, typeDeclarations, newTypeDeclarations);
311
312 TypeMirror typeMirror = mirrorInternal(type, mirrorContext);
313 while (!newTypeDeclarations.isEmpty()) {
314 List<TypeElementImpl> typeDeclarationsToFinish = new ArrayList<>(newTypeDeclarations.values());
315 typeDeclarations.putAll(newTypeDeclarations);
316 newTypeDeclarations.clear();
317 for (TypeElementImpl typeDeclaration: typeDeclarationsToFinish) {
318 typeDeclaration.finish(mirrorContext);
319 }
320 }
321 return typeMirror;
322 }
323
324 private static ImmutableList<ReflectionTypeMirror> toList(TypeMirror[] types) {
325 List<ReflectionTypeMirror> list = new ArrayList<>(types.length);
326 for (TypeMirror type: types) {
327 list.add((ReflectionTypeMirror) type);
328 }
329 return ImmutableList.copyOf(list);
330 }
331
332 @Override
333 public DeclaredType getDeclaredType(@Nullable DeclaredType containing, TypeElement typeElem,
334 TypeMirror... typeArgs) {
335 requireValidType(containing);
336 requireValidElement(typeElem);
337 requireValidTypes(typeArgs);
338
339 ReflectionTypeMirror newContainingType = containing == null
340 ? NoTypeImpl.NONE
341 : (ReflectionTypeMirror) containing;
342 return new DeclaredTypeImpl(newContainingType, (TypeElementImpl) typeElem, toList(typeArgs));
343 }
344
345 @Override
346 public DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) {
347 requireValidElement(typeElem);
348 requireValidTypes(typeArgs);
349
350 return new DeclaredTypeImpl(NoTypeImpl.NONE, (TypeElementImpl) typeElem, toList(typeArgs));
351 }
352
353 @Override
354 public NoType getNoType(TypeKind kind) {
355 Objects.requireNonNull(kind);
356 if (kind == TypeKind.VOID) {
357 return NoTypeImpl.VOID;
358 } else if (kind == TypeKind.NONE) {
359 return NoTypeImpl.NONE;
360 } else {
361 throw new IllegalArgumentException(String.format("Expected one of %s, but got %s.",
362 Arrays.asList(TypeKind.VOID, TypeKind.NONE), kind));
363 }
364 }
365
366 @Override
367 public NullType getNullType() {
368 return NullTypeImpl.INSTANCE;
369 }
370
371 @Override
372 public ArrayType getArrayType(TypeMirror componentType) {
373 Objects.requireNonNull(componentType);
374 requireValidType(componentType);
375
376 return new ArrayTypeImpl((ReflectionTypeMirror) componentType);
377 }
378
379 @Override
380 protected javax.lang.model.type.TypeVariable createTypeVariable(TypeParameterElement typeParameter,
381 @Nullable javax.lang.model.type.WildcardType capturedTypeArgument) {
382 requireValidElement(Objects.requireNonNull(typeParameter));
383 requireValidType(capturedTypeArgument);
384
385 return new TypeVariableImpl((TypeParameterElementImpl) typeParameter, (WildcardTypeImpl) capturedTypeArgument);
386 }
387
388 @Override
389 protected javax.lang.model.type.WildcardType capturedTypeArgument(javax.lang.model.type.TypeVariable typeVariable) {
390 requireValidType(Objects.requireNonNull(typeVariable));
391
392 return ((TypeVariableImpl) typeVariable).getCapturedTypeArgument();
393 }
394
395 @Override
396 public IntersectionType getIntersectionType(TypeMirror... bounds) {
397 Objects.requireNonNull(bounds);
398 if (bounds.length == 0) {
399 throw new IllegalArgumentException("Expected at least one bound.");
400 }
401 requireValidTypes(bounds);
402
403 List<ReflectionTypeMirror> newBounds = new ArrayList<>(bounds.length);
404 for (TypeMirror bound: bounds) {
405 newBounds.add((ReflectionTypeMirror) bound);
406 }
407
408 return new IntersectionTypeImpl(newBounds);
409 }
410
411 @Override
412 protected void setTypeVariableBounds(javax.lang.model.type.TypeVariable typeVariable, TypeMirror upperBound,
413 TypeMirror lowerBound) {
414 requireValidType(Objects.requireNonNull(typeVariable));
415 requireValidType(Objects.requireNonNull(upperBound));
416 requireValidType(Objects.requireNonNull(lowerBound));
417
418 ((TypeVariableImpl) typeVariable).setUpperAndLowerBounds(
419 (ReflectionTypeMirror) upperBound,
420 (ReflectionTypeMirror) lowerBound
421 );
422 }
423
424 @Override
425 public PrimitiveType getPrimitiveType(TypeKind kind) {
426 @Nullable PrimitiveTypeImpl primitiveType = primitiveTypes.get(kind.ordinal());
427 if (primitiveType == null) {
428 throw new IllegalArgumentException(String.format("Expected primitive kind, but got %s.", kind));
429 }
430 return primitiveType;
431 }
432
433 @Override
434 public javax.lang.model.type.WildcardType getWildcardType(@Nullable TypeMirror extendsBound,
435 @Nullable TypeMirror superBound) {
436 requireValidType(extendsBound);
437 requireValidType(superBound);
438
439 return new WildcardTypeImpl((ReflectionTypeMirror) extendsBound, (ReflectionTypeMirror) superBound);
440 }
441
442 private static UnsupportedOperationException unsupportedException() {
443 return new UnsupportedOperationException(
444 "isAssignable(), isSubsignature(), asMemberOf(), and directSupertypes() not currently supported."
445 );
446 }
447
448 @Override
449 public boolean isAssignable(TypeMirror t1, TypeMirror t2) {
450 throw unsupportedException();
451 }
452
453 @Override
454 public boolean isSubsignature(ExecutableType m1, ExecutableType m2) {
455 throw unsupportedException();
456 }
457
458 @Override
459 public TypeMirror asMemberOf(DeclaredType containing, Element element) {
460 throw unsupportedException();
461 }
462
463
464
465
466 @Override
467 public List<? extends TypeMirror> directSupertypes(TypeMirror t) {
468 throw unsupportedException();
469 }
470 }