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