AnnotationAnalyzer.java revision 2611838bffef5a009ca71e3e9e59a93f29b098ed
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 */ 16package android.databinding.tool.reflection.annotation; 17 18import android.databinding.tool.reflection.ModelAnalyzer; 19import android.databinding.tool.reflection.ModelClass; 20import android.databinding.tool.reflection.TypeUtil; 21import android.databinding.tool.util.L; 22 23import java.util.ArrayList; 24import java.util.HashMap; 25import java.util.Map; 26 27import javax.annotation.processing.ProcessingEnvironment; 28import javax.lang.model.element.TypeElement; 29import javax.lang.model.type.DeclaredType; 30import javax.lang.model.type.TypeKind; 31import javax.lang.model.type.TypeMirror; 32import javax.lang.model.util.Elements; 33import javax.lang.model.util.Types; 34import javax.tools.Diagnostic; 35 36public class AnnotationAnalyzer extends ModelAnalyzer { 37 38 public static final Map<String, TypeKind> PRIMITIVE_TYPES; 39 static { 40 PRIMITIVE_TYPES = new HashMap<>(); 41 PRIMITIVE_TYPES.put("boolean", TypeKind.BOOLEAN); 42 PRIMITIVE_TYPES.put("byte", TypeKind.BYTE); 43 PRIMITIVE_TYPES.put("short", TypeKind.SHORT); 44 PRIMITIVE_TYPES.put("char", TypeKind.CHAR); 45 PRIMITIVE_TYPES.put("int", TypeKind.INT); 46 PRIMITIVE_TYPES.put("long", TypeKind.LONG); 47 PRIMITIVE_TYPES.put("float", TypeKind.FLOAT); 48 PRIMITIVE_TYPES.put("double", TypeKind.DOUBLE); 49 } 50 51 public final ProcessingEnvironment mProcessingEnv; 52 53 public AnnotationAnalyzer(ProcessingEnvironment processingEnvironment) { 54 mProcessingEnv = processingEnvironment; 55 setInstance(this); 56 L.setClient(new L.Client() { 57 @Override 58 public void printMessage(Diagnostic.Kind kind, String message) { 59 mProcessingEnv.getMessager().printMessage(kind, message); 60 } 61 }); 62 } 63 64 public static AnnotationAnalyzer get() { 65 return (AnnotationAnalyzer) getInstance(); 66 } 67 68 @Override 69 public AnnotationClass loadPrimitive(String className) { 70 TypeKind typeKind = PRIMITIVE_TYPES.get(className); 71 if (typeKind == null) { 72 return null; 73 } else { 74 Types typeUtils = getTypeUtils(); 75 return new AnnotationClass(typeUtils.getPrimitiveType(typeKind)); 76 } 77 } 78 79 @Override 80 public AnnotationClass findClass(String className, Map<String, String> imports) { 81 className = className.trim(); 82 int numDimensions = 0; 83 while (className.endsWith("[]")) { 84 numDimensions++; 85 className = className.substring(0, className.length() - 2); 86 } 87 AnnotationClass primitive = loadPrimitive(className); 88 if (primitive != null) { 89 return addDimension(primitive.mTypeMirror, numDimensions); 90 } 91 int templateOpenIndex = className.indexOf('<'); 92 DeclaredType declaredType; 93 if (templateOpenIndex < 0) { 94 TypeElement typeElement = getTypeElement(className, imports); 95 if (typeElement == null) { 96 return null; 97 } 98 declaredType = (DeclaredType) typeElement.asType(); 99 } else { 100 int templateCloseIndex = className.lastIndexOf('>'); 101 String paramStr = className.substring(templateOpenIndex + 1, templateCloseIndex); 102 103 String baseClassName = className.substring(0, templateOpenIndex); 104 TypeElement typeElement = getTypeElement(baseClassName, imports); 105 if (typeElement == null) { 106 L.e("cannot find type element for %s", baseClassName); 107 return null; 108 } 109 110 ArrayList<String> templateParameters = splitTemplateParameters(paramStr); 111 TypeMirror[] typeArgs = new TypeMirror[templateParameters.size()]; 112 for (int i = 0; i < typeArgs.length; i++) { 113 final AnnotationClass clazz = findClass(templateParameters.get(i), imports); 114 if (clazz == null) { 115 L.e("cannot find type argument for %s in %s", templateParameters.get(i), 116 baseClassName); 117 return null; 118 } 119 typeArgs[i] = clazz.mTypeMirror; 120 } 121 Types typeUtils = getTypeUtils(); 122 declaredType = typeUtils.getDeclaredType(typeElement, typeArgs); 123 } 124 return addDimension(declaredType, numDimensions); 125 } 126 127 private AnnotationClass addDimension(TypeMirror type, int numDimensions) { 128 while (numDimensions > 0) { 129 type = getTypeUtils().getArrayType(type); 130 numDimensions--; 131 } 132 return new AnnotationClass(type); 133 } 134 135 private TypeElement getTypeElement(String className, Map<String, String> imports) { 136 Elements elementUtils = getElementUtils(); 137 final boolean hasDot = className.indexOf('.') >= 0; 138 if (!hasDot && imports != null) { 139 // try the imports 140 String importedClass = imports.get(className); 141 if (importedClass != null) { 142 className = importedClass; 143 } 144 } 145 if (className.indexOf('.') < 0) { 146 // try java.lang. 147 String javaLangClass = "java.lang." + className; 148 try { 149 TypeElement javaLang = elementUtils.getTypeElement(javaLangClass); 150 if (javaLang != null) { 151 return javaLang; 152 } 153 } catch (Exception e) { 154 // try the normal way 155 } 156 } 157 try { 158 TypeElement typeElement = elementUtils.getTypeElement(className); 159 if (typeElement == null && hasDot && imports != null) { 160 int lastDot = className.lastIndexOf('.'); 161 TypeElement parent = getTypeElement(className.substring(0, lastDot), imports); 162 if (parent == null) { 163 return null; 164 } 165 String name = parent.getQualifiedName() + "." + className.substring(lastDot + 1); 166 return getTypeElement(name, null); 167 } 168 return typeElement; 169 } catch (Exception e) { 170 return null; 171 } 172 } 173 174 private ArrayList<String> splitTemplateParameters(String templateParameters) { 175 ArrayList<String> list = new ArrayList<String>(); 176 int index = 0; 177 int openCount = 0; 178 StringBuilder arg = new StringBuilder(); 179 while (index < templateParameters.length()) { 180 char c = templateParameters.charAt(index); 181 if (c == ',' && openCount == 0) { 182 list.add(arg.toString()); 183 arg.delete(0, arg.length()); 184 } else if (!Character.isWhitespace(c)) { 185 arg.append(c); 186 if (c == '<') { 187 openCount++; 188 } else if (c == '>') { 189 openCount--; 190 } 191 } 192 index++; 193 } 194 list.add(arg.toString()); 195 return list; 196 } 197 198 @Override 199 public ModelClass findClass(Class classType) { 200 return findClass(classType.getCanonicalName(), null); 201 } 202 203 public Types getTypeUtils() { 204 return mProcessingEnv.getTypeUtils(); 205 } 206 207 public Elements getElementUtils() { 208 return mProcessingEnv.getElementUtils(); 209 } 210 211 public ProcessingEnvironment getProcessingEnv() { 212 return mProcessingEnv; 213 } 214 215 @Override 216 public TypeUtil createTypeUtil() { 217 return new AnnotationTypeUtil(this); 218 } 219} 220