• 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         if (that == null) {
290             return false;
291         }
292         AnnotationClass thatAnnotationClass = (AnnotationClass) that;
293         return getTypeUtils().isAssignable(thatAnnotationClass.mTypeMirror, this.mTypeMirror);
294     }
295 
296     @Override
getDeclaredMethods()297     public ModelMethod[] getDeclaredMethods() {
298         final ModelMethod[] declaredMethods;
299         if (mTypeMirror.getKind() == TypeKind.DECLARED) {
300             DeclaredType declaredType = (DeclaredType) mTypeMirror;
301             Elements elementUtils = getElementUtils();
302             TypeElement typeElement = (TypeElement) declaredType.asElement();
303             List<? extends Element> members = elementUtils.getAllMembers(typeElement);
304             List<ExecutableElement> methods = ElementFilter.methodsIn(members);
305             declaredMethods = new ModelMethod[methods.size()];
306             for (int i = 0; i < declaredMethods.length; i++) {
307                 declaredMethods[i] = new AnnotationMethod(declaredType, methods.get(i));
308             }
309         } else {
310             declaredMethods = new ModelMethod[0];
311         }
312         return declaredMethods;
313     }
314 
315     @Override
getSuperclass()316     public AnnotationClass getSuperclass() {
317         if (mTypeMirror.getKind() == TypeKind.DECLARED) {
318             DeclaredType declaredType = (DeclaredType) mTypeMirror;
319             TypeElement typeElement = (TypeElement) declaredType.asElement();
320             TypeMirror superClass = typeElement.getSuperclass();
321             if (superClass.getKind() == TypeKind.DECLARED) {
322                 return new AnnotationClass(superClass);
323             }
324         }
325         return null;
326     }
327 
328     @Override
getCanonicalName()329     public String getCanonicalName() {
330         return getTypeUtils().erasure(mTypeMirror).toString();
331     }
332 
333     @Override
erasure()334     public ModelClass erasure() {
335         final TypeMirror erasure = getTypeUtils().erasure(mTypeMirror);
336         if (erasure == mTypeMirror) {
337             return this;
338         } else {
339             return new AnnotationClass(erasure);
340         }
341     }
342 
343     @Override
getJniDescription()344     public String getJniDescription() {
345         return TypeUtil.getInstance().getDescription(this);
346     }
347 
348     @Override
getDeclaredFields()349     protected ModelField[] getDeclaredFields() {
350         final ModelField[] declaredFields;
351         if (mTypeMirror.getKind() == TypeKind.DECLARED) {
352             DeclaredType declaredType = (DeclaredType) mTypeMirror;
353             Elements elementUtils = getElementUtils();
354             TypeElement typeElement = (TypeElement) declaredType.asElement();
355             List<? extends Element> members = elementUtils.getAllMembers(typeElement);
356             List<VariableElement> fields = ElementFilter.fieldsIn(members);
357             declaredFields = new ModelField[fields.size()];
358             for (int i = 0; i < declaredFields.length; i++) {
359                 declaredFields[i] = new AnnotationField(typeElement, fields.get(i));
360             }
361         } else {
362             declaredFields = new ModelField[0];
363         }
364         return declaredFields;
365     }
366 
367     @Override
equals(Object obj)368     public boolean equals(Object obj) {
369         if (obj instanceof AnnotationClass) {
370             return getTypeUtils().isSameType(mTypeMirror, ((AnnotationClass) obj).mTypeMirror);
371         } else {
372             return false;
373         }
374     }
375 
376     @Override
hashCode()377     public int hashCode() {
378         return mTypeMirror.toString().hashCode();
379     }
380 
getTypeUtils()381     private static Types getTypeUtils() {
382         return AnnotationAnalyzer.get().mProcessingEnv.getTypeUtils();
383     }
384 
getElementUtils()385     private static Elements getElementUtils() {
386         return AnnotationAnalyzer.get().mProcessingEnv.getElementUtils();
387     }
388 
389     @Override
toString()390     public String toString() {
391         return mTypeMirror.toString();
392     }
393 }
394