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