• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.databinding.tool.reflection.annotation;
17 
18 import android.databinding.tool.reflection.ModelAnalyzer;
19 import android.databinding.tool.reflection.ModelClass;
20 import android.databinding.tool.reflection.ModelField;
21 import android.databinding.tool.reflection.ModelMethod;
22 import android.databinding.tool.reflection.TypeUtil;
23 import android.databinding.tool.util.L;
24 
25 import java.util.ArrayList;
26 import java.util.List;
27 
28 import javax.lang.model.element.AnnotationMirror;
29 import javax.lang.model.element.AnnotationValue;
30 import javax.lang.model.element.Element;
31 import javax.lang.model.element.ElementKind;
32 import javax.lang.model.element.ExecutableElement;
33 import javax.lang.model.element.TypeElement;
34 import javax.lang.model.element.VariableElement;
35 import javax.lang.model.type.ArrayType;
36 import javax.lang.model.type.DeclaredType;
37 import javax.lang.model.type.PrimitiveType;
38 import javax.lang.model.type.TypeKind;
39 import javax.lang.model.type.TypeMirror;
40 import javax.lang.model.util.ElementFilter;
41 import javax.lang.model.util.Elements;
42 import javax.lang.model.util.Types;
43 
44 /**
45  * This is the implementation of ModelClass for the annotation
46  * processor. It relies on AnnotationAnalyzer.
47  */
48 class AnnotationClass extends ModelClass {
49 
50     final TypeMirror mTypeMirror;
51 
AnnotationClass(TypeMirror typeMirror)52     public AnnotationClass(TypeMirror typeMirror) {
53         mTypeMirror = typeMirror;
54     }
55 
56     @Override
toJavaCode()57     public String toJavaCode() {
58         if (isIncomplete()) {
59             return getCanonicalName();
60         }
61         return mTypeMirror.toString();
62     }
63 
64     @Override
isArray()65     public boolean isArray() {
66         return mTypeMirror.getKind() == TypeKind.ARRAY;
67     }
68 
69     @Override
getComponentType()70     public AnnotationClass getComponentType() {
71         TypeMirror component = null;
72         if (isArray()) {
73             component = ((ArrayType) mTypeMirror).getComponentType();
74         } else if (isList()) {
75             for (ModelMethod method : getMethods("get", 1)) {
76                 ModelClass parameter = method.getParameterTypes()[0];
77                 if (parameter.isInt() || parameter.isLong()) {
78                     ArrayList<ModelClass> parameters = new ArrayList<ModelClass>(1);
79                     parameters.add(parameter);
80                     return (AnnotationClass) method.getReturnType(parameters);
81                 }
82             }
83             // no "get" call found!
84             return null;
85         } else {
86             AnnotationClass mapClass = (AnnotationClass) ModelAnalyzer.getInstance().getMapType();
87             DeclaredType mapType = findInterface(mapClass.mTypeMirror);
88             if (mapType == null) {
89                 return null;
90             }
91             component = mapType.getTypeArguments().get(1);
92         }
93 
94         return new AnnotationClass(component);
95     }
96 
findInterface(TypeMirror interfaceType)97     private DeclaredType findInterface(TypeMirror interfaceType) {
98         Types typeUtil = getTypeUtils();
99         TypeMirror foundInterface = null;
100         if (typeUtil.isSameType(interfaceType, typeUtil.erasure(mTypeMirror))) {
101             foundInterface = mTypeMirror;
102         } else {
103             ArrayList<TypeMirror> toCheck = new ArrayList<TypeMirror>();
104             toCheck.add(mTypeMirror);
105             while (!toCheck.isEmpty()) {
106                 TypeMirror typeMirror = toCheck.remove(0);
107                 if (typeUtil.isSameType(interfaceType, typeUtil.erasure(typeMirror))) {
108                     foundInterface = typeMirror;
109                     break;
110                 } else {
111                     toCheck.addAll(typeUtil.directSupertypes(typeMirror));
112                 }
113             }
114             if (foundInterface == null) {
115                 L.e("Detected " + interfaceType + " type for " + mTypeMirror +
116                         ", but not able to find the implemented interface.");
117                 return null;
118             }
119         }
120         if (foundInterface.getKind() != TypeKind.DECLARED) {
121             L.e("Found " + interfaceType + " type for " + mTypeMirror +
122                     ", but it isn't a declared type: " + foundInterface);
123             return null;
124         }
125         return (DeclaredType) foundInterface;
126     }
127 
128     @Override
isNullable()129     public boolean isNullable() {
130         switch (mTypeMirror.getKind()) {
131             case ARRAY:
132             case DECLARED:
133             case NULL:
134                 return true;
135             default:
136                 return false;
137         }
138     }
139 
140     @Override
isPrimitive()141     public boolean isPrimitive() {
142         switch (mTypeMirror.getKind()) {
143             case BOOLEAN:
144             case BYTE:
145             case SHORT:
146             case INT:
147             case LONG:
148             case CHAR:
149             case FLOAT:
150             case DOUBLE:
151                 return true;
152             default:
153                 return false;
154         }
155     }
156 
157     @Override
isBoolean()158     public boolean isBoolean() {
159         return mTypeMirror.getKind() == TypeKind.BOOLEAN;
160     }
161 
162     @Override
isChar()163     public boolean isChar() {
164         return mTypeMirror.getKind() == TypeKind.CHAR;
165     }
166 
167     @Override
isByte()168     public boolean isByte() {
169         return mTypeMirror.getKind() == TypeKind.BYTE;
170     }
171 
172     @Override
isShort()173     public boolean isShort() {
174         return mTypeMirror.getKind() == TypeKind.SHORT;
175     }
176 
177     @Override
isInt()178     public boolean isInt() {
179         return mTypeMirror.getKind() == TypeKind.INT;
180     }
181 
182     @Override
isLong()183     public boolean isLong() {
184         return mTypeMirror.getKind() == TypeKind.LONG;
185     }
186 
187     @Override
isFloat()188     public boolean isFloat() {
189         return mTypeMirror.getKind() == TypeKind.FLOAT;
190     }
191 
192     @Override
isDouble()193     public boolean isDouble() {
194         return mTypeMirror.getKind() == TypeKind.DOUBLE;
195     }
196 
197     @Override
isGeneric()198     public boolean isGeneric() {
199         boolean isGeneric = false;
200         if (mTypeMirror.getKind() == TypeKind.DECLARED) {
201             DeclaredType declaredType = (DeclaredType) mTypeMirror;
202             List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
203             isGeneric = typeArguments != null && !typeArguments.isEmpty();
204         }
205         return isGeneric;
206     }
207 
208     @Override
getMinApi()209     public int getMinApi() {
210         if (mTypeMirror.getKind() == TypeKind.DECLARED) {
211             DeclaredType declaredType = (DeclaredType) mTypeMirror;
212             List<? extends AnnotationMirror> annotations =
213                     getElementUtils().getAllAnnotationMirrors(declaredType.asElement());
214 
215             TypeElement targetApi = getElementUtils().getTypeElement("android.annotation.TargetApi");
216             TypeMirror targetApiType = targetApi.asType();
217             Types typeUtils = getTypeUtils();
218             for (AnnotationMirror annotation : annotations) {
219                 if (typeUtils.isAssignable(annotation.getAnnotationType(), targetApiType)) {
220                     for (AnnotationValue value : annotation.getElementValues().values()) {
221                         return (Integer) value.getValue();
222                     }
223                 }
224             }
225         }
226         return super.getMinApi();
227     }
228 
229     @Override
getTypeArguments()230     public List<ModelClass> getTypeArguments() {
231         List<ModelClass> types = null;
232         if (mTypeMirror.getKind() == TypeKind.DECLARED) {
233             DeclaredType declaredType = (DeclaredType) mTypeMirror;
234             List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
235             if (typeArguments != null && !typeArguments.isEmpty()) {
236                 types = new ArrayList<ModelClass>();
237                 for (TypeMirror typeMirror : typeArguments) {
238                     types.add(new AnnotationClass(typeMirror));
239                 }
240             }
241         }
242         return types;
243     }
244 
245     @Override
isTypeVar()246     public boolean isTypeVar() {
247         return mTypeMirror.getKind() == TypeKind.TYPEVAR;
248     }
249 
250     @Override
isWildcard()251     public boolean isWildcard() {
252         return mTypeMirror.getKind() == TypeKind.WILDCARD;
253     }
254 
255     @Override
isInterface()256     public boolean isInterface() {
257         return mTypeMirror.getKind() == TypeKind.DECLARED &&
258                 ((DeclaredType)mTypeMirror).asElement().getKind() == ElementKind.INTERFACE;
259     }
260 
261     @Override
isVoid()262     public boolean isVoid() {
263         return mTypeMirror.getKind() == TypeKind.VOID;
264     }
265 
266     @Override
unbox()267     public AnnotationClass unbox() {
268         if (!isNullable()) {
269             return this;
270         }
271         try {
272             return new AnnotationClass(getTypeUtils().unboxedType(mTypeMirror));
273         } catch (IllegalArgumentException e) {
274             // I'm being lazy. This is much easier than checking every type.
275             return this;
276         }
277     }
278 
279     @Override
box()280     public AnnotationClass box() {
281         if (!isPrimitive()) {
282             return this;
283         }
284         return new AnnotationClass(getTypeUtils().boxedClass((PrimitiveType) mTypeMirror).asType());
285     }
286 
287     @Override
isAssignableFrom(ModelClass that)288     public boolean isAssignableFrom(ModelClass that) {
289         ModelClass other = that;
290         while (other != null && !(other instanceof AnnotationClass)) {
291             other = other.getSuperclass();
292         }
293         if (other == null) {
294             return false;
295         }
296         if (equals(other)) {
297             return true;
298         }
299         AnnotationClass thatAnnotationClass = (AnnotationClass) other;
300         return getTypeUtils().isAssignable(thatAnnotationClass.mTypeMirror, this.mTypeMirror);
301     }
302 
303     @Override
getDeclaredMethods()304     public ModelMethod[] getDeclaredMethods() {
305         final ModelMethod[] declaredMethods;
306         if (mTypeMirror.getKind() == TypeKind.DECLARED) {
307             DeclaredType declaredType = (DeclaredType) mTypeMirror;
308             Elements elementUtils = getElementUtils();
309             TypeElement typeElement = (TypeElement) declaredType.asElement();
310             List<? extends Element> members = elementUtils.getAllMembers(typeElement);
311             List<ExecutableElement> methods = ElementFilter.methodsIn(members);
312             declaredMethods = new ModelMethod[methods.size()];
313             for (int i = 0; i < declaredMethods.length; i++) {
314                 declaredMethods[i] = new AnnotationMethod(declaredType, methods.get(i));
315             }
316         } else {
317             declaredMethods = new ModelMethod[0];
318         }
319         return declaredMethods;
320     }
321 
322     @Override
getSuperclass()323     public AnnotationClass getSuperclass() {
324         if (mTypeMirror.getKind() == TypeKind.DECLARED) {
325             DeclaredType declaredType = (DeclaredType) mTypeMirror;
326             TypeElement typeElement = (TypeElement) declaredType.asElement();
327             TypeMirror superClass = typeElement.getSuperclass();
328             if (superClass.getKind() == TypeKind.DECLARED) {
329                 return new AnnotationClass(superClass);
330             }
331         }
332         return null;
333     }
334 
335     @Override
getCanonicalName()336     public String getCanonicalName() {
337         return getTypeUtils().erasure(mTypeMirror).toString();
338     }
339 
340     @Override
erasure()341     public ModelClass erasure() {
342         final TypeMirror erasure = getTypeUtils().erasure(mTypeMirror);
343         if (erasure == mTypeMirror) {
344             return this;
345         } else {
346             return new AnnotationClass(erasure);
347         }
348     }
349 
350     @Override
getJniDescription()351     public String getJniDescription() {
352         return TypeUtil.getInstance().getDescription(this);
353     }
354 
355     @Override
getDeclaredFields()356     protected ModelField[] getDeclaredFields() {
357         final ModelField[] declaredFields;
358         if (mTypeMirror.getKind() == TypeKind.DECLARED) {
359             DeclaredType declaredType = (DeclaredType) mTypeMirror;
360             Elements elementUtils = getElementUtils();
361             TypeElement typeElement = (TypeElement) declaredType.asElement();
362             List<? extends Element> members = elementUtils.getAllMembers(typeElement);
363             List<VariableElement> fields = ElementFilter.fieldsIn(members);
364             declaredFields = new ModelField[fields.size()];
365             for (int i = 0; i < declaredFields.length; i++) {
366                 declaredFields[i] = new AnnotationField(typeElement, fields.get(i));
367             }
368         } else {
369             declaredFields = new ModelField[0];
370         }
371         return declaredFields;
372     }
373 
getTypeUtils()374     private static Types getTypeUtils() {
375         return AnnotationAnalyzer.get().mProcessingEnv.getTypeUtils();
376     }
377 
getElementUtils()378     private static Elements getElementUtils() {
379         return AnnotationAnalyzer.get().mProcessingEnv.getElementUtils();
380     }
381 
382     @Override
toString()383     public String toString() {
384         return mTypeMirror.toString();
385     }
386 
387     @Override
equals(Object obj)388     public boolean equals(Object obj) {
389         if (obj instanceof AnnotationClass) {
390             return getTypeUtils().isSameType(mTypeMirror, ((AnnotationClass) obj).mTypeMirror);
391         } else {
392             return false;
393         }
394     }
395 
396     @Override
hashCode()397     public int hashCode() {
398         return mTypeMirror.toString().hashCode();
399     }
400 }
401