AnnotationAnalyzer.java revision b9e4aa96812692a7dcf468445e64bc5b30d3c79a
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 com.google.common.collect.ImmutableMap; 19 20import android.databinding.tool.reflection.ModelAnalyzer; 21import android.databinding.tool.reflection.ModelClass; 22import android.databinding.tool.reflection.TypeUtil; 23import android.databinding.tool.util.L; 24 25import java.util.ArrayList; 26import java.util.Map; 27 28import javax.annotation.processing.ProcessingEnvironment; 29import javax.lang.model.element.TypeElement; 30import javax.lang.model.type.DeclaredType; 31import javax.lang.model.type.TypeKind; 32import javax.lang.model.type.TypeMirror; 33import javax.lang.model.util.Elements; 34import javax.lang.model.util.Types; 35 36public class AnnotationAnalyzer extends ModelAnalyzer { 37 38 public static final Map<String, TypeKind> PRIMITIVE_TYPES = 39 new ImmutableMap.Builder<String, TypeKind>() 40 .put("boolean", TypeKind.BOOLEAN) 41 .put("byte", TypeKind.BYTE) 42 .put("short", TypeKind.SHORT) 43 .put("char", TypeKind.CHAR) 44 .put("int", TypeKind.INT) 45 .put("long", TypeKind.LONG) 46 .put("float", TypeKind.FLOAT) 47 .put("double", TypeKind.DOUBLE) 48 .build(); 49 50 public final ProcessingEnvironment mProcessingEnv; 51 52 public AnnotationAnalyzer(ProcessingEnvironment processingEnvironment) { 53 mProcessingEnv = processingEnvironment; 54 setInstance(this); 55 } 56 57 public static AnnotationAnalyzer get() { 58 return (AnnotationAnalyzer) getInstance(); 59 } 60 61 @Override 62 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 final AnnotationClass clazz = findClass(templateParameters.get(i), imports); 107 if (clazz == null) { 108 L.e("cannot find type argument for %s in %s", templateParameters.get(i), 109 baseClassName); 110 return null; 111 } 112 typeArgs[i] = clazz.mTypeMirror; 113 } 114 Types typeUtils = getTypeUtils(); 115 declaredType = typeUtils.getDeclaredType(typeElement, typeArgs); 116 } 117 return addDimension(declaredType, numDimensions); 118 } 119 120 private AnnotationClass addDimension(TypeMirror type, int numDimensions) { 121 while (numDimensions > 0) { 122 type = getTypeUtils().getArrayType(type); 123 numDimensions--; 124 } 125 return new AnnotationClass(type); 126 } 127 128 private TypeElement getTypeElement(String className, Map<String, String> imports) { 129 Elements elementUtils = getElementUtils(); 130 final boolean hasDot = className.indexOf('.') >= 0; 131 if (!hasDot && imports != null) { 132 // try the imports 133 String importedClass = imports.get(className); 134 if (importedClass != null) { 135 className = importedClass; 136 } 137 } 138 if (className.indexOf('.') < 0) { 139 // try java.lang. 140 String javaLangClass = "java.lang." + className; 141 try { 142 TypeElement javaLang = elementUtils.getTypeElement(javaLangClass); 143 if (javaLang != null) { 144 return javaLang; 145 } 146 } catch (Exception e) { 147 // try the normal way 148 } 149 } 150 try { 151 TypeElement typeElement = elementUtils.getTypeElement(className); 152 if (typeElement == null && hasDot && imports != null) { 153 int lastDot = className.lastIndexOf('.'); 154 TypeElement parent = getTypeElement(className.substring(0, lastDot), imports); 155 if (parent == null) { 156 return null; 157 } 158 String name = parent.getQualifiedName() + "." + className.substring(lastDot + 1); 159 return getTypeElement(name, null); 160 } 161 return typeElement; 162 } catch (Exception e) { 163 return null; 164 } 165 } 166 167 private ArrayList<String> splitTemplateParameters(String templateParameters) { 168 ArrayList<String> list = new ArrayList<String>(); 169 int index = 0; 170 int openCount = 0; 171 StringBuilder arg = new StringBuilder(); 172 while (index < templateParameters.length()) { 173 char c = templateParameters.charAt(index); 174 if (c == ',' && openCount == 0) { 175 list.add(arg.toString()); 176 arg.delete(0, arg.length()); 177 } else if (!Character.isWhitespace(c)) { 178 arg.append(c); 179 if (c == '<') { 180 openCount++; 181 } else if (c == '>') { 182 openCount--; 183 } 184 } 185 index++; 186 } 187 list.add(arg.toString()); 188 return list; 189 } 190 191 @Override 192 public ModelClass findClass(Class classType) { 193 return findClass(classType.getCanonicalName(), null); 194 } 195 196 public Types getTypeUtils() { 197 return mProcessingEnv.getTypeUtils(); 198 } 199 200 public Elements getElementUtils() { 201 return mProcessingEnv.getElementUtils(); 202 } 203 204 public ProcessingEnvironment getProcessingEnv() { 205 return mProcessingEnv; 206 } 207 208 @Override 209 public TypeUtil createTypeUtil() { 210 return new AnnotationTypeUtil(this); 211 } 212} 213