AnnotationAnalyzer.java revision fead9ca09b117136b35bc5bf137340a754f9eddd
15bc087c573c70c84c6a39946457590b42d392a33Andreas Huber/* 25bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * Copyright (C) 2015 The Android Open Source Project 35bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * 45bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 55bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * you may not use this file except in compliance with the License. 65bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * You may obtain a copy of the License at 75bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * 85bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * http://www.apache.org/licenses/LICENSE-2.0 95bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * 105bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * Unless required by applicable law or agreed to in writing, software 115bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 125bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * See the License for the specific language governing permissions and 145bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * limitations under the License. 155bc087c573c70c84c6a39946457590b42d392a33Andreas Huber */ 165bc087c573c70c84c6a39946457590b42d392a33Andreas Huberpackage android.databinding.tool.reflection.annotation; 175bc087c573c70c84c6a39946457590b42d392a33Andreas Huber 185bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport com.google.common.collect.ImmutableMap; 195bc087c573c70c84c6a39946457590b42d392a33Andreas Huber 205bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport android.databinding.tool.reflection.ModelAnalyzer; 215bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport android.databinding.tool.reflection.ModelClass; 225bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport android.databinding.tool.reflection.TypeUtil; 235bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport android.databinding.tool.util.L; 245bc087c573c70c84c6a39946457590b42d392a33Andreas Huber 255bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport java.util.ArrayList; 265bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport java.util.Map; 275bc087c573c70c84c6a39946457590b42d392a33Andreas Huber 285bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport javax.annotation.processing.ProcessingEnvironment; 295bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport javax.lang.model.element.TypeElement; 305bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport javax.lang.model.type.DeclaredType; 315bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport javax.lang.model.type.TypeKind; 325bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport javax.lang.model.type.TypeMirror; 335bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport javax.lang.model.util.Elements; 345bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport javax.lang.model.util.Types; 355bc087c573c70c84c6a39946457590b42d392a33Andreas Huber 365bc087c573c70c84c6a39946457590b42d392a33Andreas Huberpublic class AnnotationAnalyzer extends ModelAnalyzer { 375bc087c573c70c84c6a39946457590b42d392a33Andreas Huber 385bc087c573c70c84c6a39946457590b42d392a33Andreas Huber public static final Map<String, TypeKind> PRIMITIVE_TYPES = 395bc087c573c70c84c6a39946457590b42d392a33Andreas Huber new ImmutableMap.Builder<String, TypeKind>() 4043c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber .put("boolean", TypeKind.BOOLEAN) 4143c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber .put("byte", TypeKind.BYTE) 4243c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber .put("short", TypeKind.SHORT) 4343c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber .put("char", TypeKind.CHAR) 4443c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber .put("int", TypeKind.INT) 4543c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber .put("long", TypeKind.LONG) 4643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber .put("float", TypeKind.FLOAT) 4743c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber .put("double", TypeKind.DOUBLE) 4843c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber .build(); 4943c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber 5043c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber public final ProcessingEnvironment mProcessingEnv; 5143c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber 525bc087c573c70c84c6a39946457590b42d392a33Andreas Huber public AnnotationAnalyzer(ProcessingEnvironment processingEnvironment) { 535bc087c573c70c84c6a39946457590b42d392a33Andreas Huber mProcessingEnv = processingEnvironment; 545bc087c573c70c84c6a39946457590b42d392a33Andreas Huber setInstance(this); 555bc087c573c70c84c6a39946457590b42d392a33Andreas Huber } 565bc087c573c70c84c6a39946457590b42d392a33Andreas Huber 575bc087c573c70c84c6a39946457590b42d392a33Andreas Huber public static AnnotationAnalyzer get() { 585bc087c573c70c84c6a39946457590b42d392a33Andreas Huber return (AnnotationAnalyzer) getInstance(); 595bc087c573c70c84c6a39946457590b42d392a33Andreas Huber } 605bc087c573c70c84c6a39946457590b42d392a33Andreas Huber 615bc087c573c70c84c6a39946457590b42d392a33Andreas Huber @Override 625bc087c573c70c84c6a39946457590b42d392a33Andreas Huber public AnnotationClass loadPrimitive(String className) { 63 TypeKind typeKind = PRIMITIVE_TYPES.get(className); 64 if (typeKind == null) { 65 return null; 66 } else { 67 Types typeUtils = getTypeUtils(); 68 return new AnnotationClass(typeUtils.getPrimitiveType(typeKind)); 69 } 70 } 71 72 @Override 73 public AnnotationClass findClass(String className, Map<String, String> imports) { 74 className = className.trim(); 75 int numDimensions = 0; 76 while (className.endsWith("[]")) { 77 numDimensions++; 78 className = className.substring(0, className.length() - 2); 79 } 80 AnnotationClass primitive = loadPrimitive(className); 81 if (primitive != null) { 82 return addDimension(primitive.mTypeMirror, numDimensions); 83 } 84 int templateOpenIndex = className.indexOf('<'); 85 DeclaredType declaredType; 86 if (templateOpenIndex < 0) { 87 TypeElement typeElement = getTypeElement(className, imports); 88 if (typeElement == null) { 89 return null; 90 } 91 declaredType = (DeclaredType) typeElement.asType(); 92 } else { 93 int templateCloseIndex = className.lastIndexOf('>'); 94 String paramStr = className.substring(templateOpenIndex + 1, templateCloseIndex); 95 96 String baseClassName = className.substring(0, templateOpenIndex); 97 TypeElement typeElement = getTypeElement(baseClassName, imports); 98 if (typeElement == null) { 99 L.e("cannot find type element for %s", baseClassName); 100 return null; 101 } 102 103 ArrayList<String> templateParameters = splitTemplateParameters(paramStr); 104 TypeMirror[] typeArgs = new TypeMirror[templateParameters.size()]; 105 for (int i = 0; i < typeArgs.length; i++) { 106 typeArgs[i] = findClass(templateParameters.get(i), imports).mTypeMirror; 107 if (typeArgs[i] == null) { 108 L.e("cannot find type argument for %s in %s", templateParameters.get(i), 109 baseClassName); 110 return null; 111 } 112 } 113 Types typeUtils = getTypeUtils(); 114 declaredType = typeUtils.getDeclaredType(typeElement, typeArgs); 115 } 116 return addDimension(declaredType, numDimensions); 117 } 118 119 private AnnotationClass addDimension(TypeMirror type, int numDimensions) { 120 while (numDimensions > 0) { 121 type = getTypeUtils().getArrayType(type); 122 numDimensions--; 123 } 124 return new AnnotationClass(type); 125 } 126 127 private TypeElement getTypeElement(String className, Map<String, String> imports) { 128 Elements elementUtils = getElementUtils(); 129 if (className.indexOf('.') < 0 && imports != null) { 130 // try the imports 131 String importedClass = imports.get(className); 132 if (importedClass != null) { 133 className = importedClass; 134 } 135 } 136 if (className.indexOf('.') < 0) { 137 // try java.lang. 138 String javaLangClass = "java.lang." + className; 139 try { 140 TypeElement javaLang = elementUtils.getTypeElement(javaLangClass); 141 if (javaLang != null) { 142 return javaLang; 143 } 144 } catch (Exception e) { 145 // try the normal way 146 } 147 } 148 try { 149 return elementUtils.getTypeElement(className); 150 } catch (Exception e) { 151 return null; 152 } 153 } 154 155 private ArrayList<String> splitTemplateParameters(String templateParameters) { 156 ArrayList<String> list = new ArrayList<String>(); 157 int index = 0; 158 int openCount = 0; 159 StringBuilder arg = new StringBuilder(); 160 while (index < templateParameters.length()) { 161 char c = templateParameters.charAt(index); 162 if (c == ',' && openCount == 0) { 163 list.add(arg.toString()); 164 arg.delete(0, arg.length()); 165 } else if (!Character.isWhitespace(c)) { 166 arg.append(c); 167 if (c == '<') { 168 openCount++; 169 } else if (c == '>') { 170 openCount--; 171 } 172 } 173 index++; 174 } 175 list.add(arg.toString()); 176 return list; 177 } 178 179 @Override 180 public ModelClass findClass(Class classType) { 181 return findClass(classType.getCanonicalName(), null); 182 } 183 184 public Types getTypeUtils() { 185 return mProcessingEnv.getTypeUtils(); 186 } 187 188 public Elements getElementUtils() { 189 return mProcessingEnv.getElementUtils(); 190 } 191 192 public ProcessingEnvironment getProcessingEnv() { 193 return mProcessingEnv; 194 } 195 196 @Override 197 public TypeUtil createTypeUtil() { 198 return new AnnotationTypeUtil(this); 199 } 200} 201