1 package net.florianschoppmann.java.reflect;
2
3 import javax.annotation.Nullable;
4 import javax.lang.model.element.ElementKind;
5 import javax.lang.model.element.ElementVisitor;
6 import javax.lang.model.element.Name;
7 import javax.lang.model.element.NestingKind;
8 import javax.lang.model.element.TypeElement;
9 import javax.lang.model.type.TypeMirror;
10 import java.lang.reflect.Type;
11 import java.lang.reflect.TypeVariable;
12 import java.util.ArrayList;
13 import java.util.List;
14 import java.util.Objects;
15
16 final class TypeElementImpl extends ElementImpl implements TypeElement, ReflectionParameterizable {
17 private final Class<?> clazz;
18 private final ImmutableList<TypeParameterElementImpl> typeParameters;
19 @Nullable private ReflectionElement enclosingElement;
20 @Nullable private ReflectionTypeMirror superClass;
21 @Nullable private List<ReflectionTypeMirror> interfaces;
22 @Nullable private List<ElementImpl> enclosedElements;
23
24
25
26
27
28
29
30
31
32
33 @Nullable private DeclaredTypeImpl type;
34
35 TypeElementImpl(Class<?> clazz) {
36 this.clazz = Objects.requireNonNull(clazz);
37
38 List<TypeParameterElementImpl> newTypeParameters = new ArrayList<>();
39 for (TypeVariable<?> parameter: clazz.getTypeParameters()) {
40 newTypeParameters.add(new TypeParameterElementImpl(parameter, this));
41 }
42 typeParameters = ImmutableList.copyOf(newTypeParameters);
43 }
44
45 @Override
46 public boolean equals(@Nullable Object otherObject) {
47 if (this == otherObject) {
48 return true;
49 } else if (otherObject == null || getClass() != otherObject.getClass()) {
50 return false;
51 }
52
53 return clazz.equals(((TypeElementImpl) otherObject).clazz);
54 }
55
56 @Override
57 public int hashCode() {
58 return clazz.hashCode();
59 }
60
61 @Override
62 public String toString() {
63 return clazz.toString();
64 }
65
66 @Override
67 public <R, P> R accept(ElementVisitor<R, P> visitor, @Nullable P parameter) {
68 return visitor.visitType(this, parameter);
69 }
70
71 @Override
72 public List<ElementImpl> getEnclosedElements() {
73 requireFinished();
74 assert enclosedElements != null : "must be non-null when finished";
75 return enclosedElements;
76 }
77
78 @Override
79 public NestingKind getNestingKind() {
80 throw new UnsupportedOperationException(String.format(
81 "Nesting kind not currently supported by %s.", ReflectionTypes.class
82 ));
83 }
84
85 @Override
86 public NameImpl getQualifiedName() {
87 return new NameImpl(clazz.getCanonicalName());
88 }
89
90 @Override
91 public Name getSimpleName() {
92 return new NameImpl(clazz.getSimpleName());
93 }
94
95 @Override
96 public TypeMirror getSuperclass() {
97 requireFinished();
98 assert superClass != null : "must be non-null when finished";
99 return superClass;
100 }
101
102 @Override
103 public List<? extends TypeMirror> getInterfaces() {
104 requireFinished();
105 assert interfaces != null : "must be non-null when finished";
106 return interfaces;
107 }
108
109 @Override
110 public List<TypeParameterElementImpl> getTypeParameters() {
111 return typeParameters;
112 }
113
114 @Override
115 public ReflectionElement getEnclosingElement() {
116 requireFinished();
117
118 if (enclosingElement == null) {
119 throw new UnsupportedOperationException("getEnclosingElement() not supported for top-level classes.");
120 } else {
121 return enclosingElement;
122 }
123 }
124
125 @Override
126 public DeclaredTypeImpl asType() {
127 requireFinished();
128
129 @Nullable DeclaredTypeImpl localType = type;
130 if (localType == null) {
131 List<TypeVariableImpl> prototypicalTypeArguments = new ArrayList<>(typeParameters.size());
132 for (TypeParameterElementImpl typeParameter: typeParameters) {
133 prototypicalTypeArguments.add(typeParameter.asType());
134 }
135
136 ReflectionTypeMirror enclosingType = enclosingElement == null
137 ? NoTypeImpl.NONE
138 : enclosingElement.asType();
139 localType = new DeclaredTypeImpl(enclosingType, this, prototypicalTypeArguments);
140 type = localType;
141 }
142 return localType;
143 }
144
145 @Override
146 public ElementKind getKind() {
147 if (clazz.isEnum()) {
148 return ElementKind.ENUM;
149 } else if (clazz.isAnnotation()) {
150 return ElementKind.ANNOTATION_TYPE;
151 } else if (clazz.isInterface()) {
152 return ElementKind.INTERFACE;
153 } else {
154 return ElementKind.CLASS;
155 }
156 }
157
158 @Override
159 protected void finishDerivedFromElement(MirrorContext mirrorContext) {
160 @Nullable Class<?> enclosingClass = clazz.getEnclosingClass();
161 enclosingElement = enclosingClass == null
162 ? null
163 : mirrorContext.typeDeclaration(enclosingClass);
164
165 Class<?>[] declaredClasses = clazz.getDeclaredClasses();
166 List<ElementImpl> newEnclosedElements = new ArrayList<>(typeParameters.size() + declaredClasses.length);
167 newEnclosedElements.addAll(typeParameters);
168 for (Class<?> declaredClass: declaredClasses) {
169 newEnclosedElements.add(mirrorContext.typeDeclaration(declaredClass));
170 }
171 enclosedElements = ImmutableList.copyOf(newEnclosedElements);
172
173 @Nullable Type genericSuperClass = clazz.getGenericSuperclass();
174 superClass = genericSuperClass == null
175 ? NoTypeImpl.NONE
176 : mirrorContext.mirror(genericSuperClass);
177 interfaces = mirrorContext.mirror(clazz.getGenericInterfaces());
178 for (TypeParameterElementImpl typeParameter: typeParameters) {
179 typeParameter.finish(mirrorContext);
180 }
181
182
183
184 }
185 }