• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.databinding.annotationprocessor;
18 
19 import android.databinding.BindingBuildInfo;
20 import android.databinding.tool.CompilerChef;
21 import android.databinding.tool.processing.Scope;
22 import android.databinding.tool.reflection.ModelAnalyzer;
23 import android.databinding.tool.util.Preconditions;
24 import android.databinding.tool.writer.AnnotationJavaFileWriter;
25 import android.databinding.tool.writer.BRWriter;
26 import android.databinding.tool.writer.JavaFileWriter;
27 
28 import java.util.Arrays;
29 import java.util.List;
30 import java.util.Set;
31 
32 import javax.annotation.processing.AbstractProcessor;
33 import javax.annotation.processing.ProcessingEnvironment;
34 import javax.annotation.processing.RoundEnvironment;
35 import javax.annotation.processing.SupportedAnnotationTypes;
36 import javax.annotation.processing.SupportedSourceVersion;
37 import javax.lang.model.SourceVersion;
38 import javax.lang.model.element.TypeElement;
39 
40 @SupportedAnnotationTypes({
41         "android.databinding.BindingAdapter",
42         "android.databinding.Untaggable",
43         "android.databinding.BindingMethods",
44         "android.databinding.BindingConversion",
45         "android.databinding.BindingBuildInfo"}
46 )
47 @SupportedSourceVersion(SourceVersion.RELEASE_7)
48 /**
49  * Parent annotation processor that dispatches sub steps to ensure execution order.
50  * Use initProcessingSteps to add a new step.
51  */
52 public class ProcessDataBinding extends AbstractProcessor {
53     private List<ProcessingStep> mProcessingSteps;
54     @Override
process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)55     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
56         if (mProcessingSteps == null) {
57             initProcessingSteps();
58         }
59         final BindingBuildInfo buildInfo = BuildInfoUtil.load(roundEnv);
60         if (buildInfo == null) {
61             return false;
62         }
63         boolean done = true;
64         for (ProcessingStep step : mProcessingSteps) {
65             done = step.runStep(roundEnv, processingEnv, buildInfo) && done;
66         }
67         if (roundEnv.processingOver()) {
68             for (ProcessingStep step : mProcessingSteps) {
69                 step.onProcessingOver(roundEnv, processingEnv, buildInfo);
70             }
71         }
72         Scope.assertNoError();
73         return done;
74     }
75 
initProcessingSteps()76     private void initProcessingSteps() {
77         final ProcessBindable processBindable = new ProcessBindable();
78         mProcessingSteps = Arrays.asList(
79                 new ProcessMethodAdapters(),
80                 new ProcessExpressions(),
81                 processBindable
82         );
83         Callback dataBinderWriterCallback = new Callback() {
84             CompilerChef mChef;
85             BRWriter mBRWriter;
86             boolean mLibraryProject;
87             int mMinSdk;
88 
89             @Override
90             public void onChefReady(CompilerChef chef, boolean libraryProject, int minSdk) {
91                 Preconditions.checkNull(mChef, "Cannot set compiler chef twice");
92                 chef.addBRVariables(processBindable);
93                 mChef = chef;
94                 mLibraryProject = libraryProject;
95                 mMinSdk = minSdk;
96                 considerWritingMapper();
97             }
98 
99             private void considerWritingMapper() {
100                 if (mLibraryProject || mChef == null || mBRWriter == null) {
101                     return;
102                 }
103                 mChef.writeDataBinderMapper(mMinSdk, mBRWriter);
104             }
105 
106             @Override
107             public void onBrWriterReady(BRWriter brWriter) {
108                 Preconditions.checkNull(mBRWriter, "Cannot set br writer twice");
109                 mBRWriter = brWriter;
110                 considerWritingMapper();
111             }
112         };
113         AnnotationJavaFileWriter javaFileWriter = new AnnotationJavaFileWriter(processingEnv);
114         for (ProcessingStep step : mProcessingSteps) {
115             step.mJavaFileWriter = javaFileWriter;
116             step.mCallback = dataBinderWriterCallback;
117         }
118     }
119 
120     @Override
init(ProcessingEnvironment processingEnv)121     public synchronized void init(ProcessingEnvironment processingEnv) {
122         super.init(processingEnv);
123         ModelAnalyzer.setProcessingEnvironment(processingEnv);
124     }
125 
126     /**
127      * To ensure execution order and binding build information, we use processing steps.
128      */
129     public abstract static class ProcessingStep {
130         private boolean mDone;
131         private JavaFileWriter mJavaFileWriter;
132         protected Callback mCallback;
133 
getWriter()134         protected JavaFileWriter getWriter() {
135             return mJavaFileWriter;
136         }
137 
runStep(RoundEnvironment roundEnvironment, ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo)138         private boolean runStep(RoundEnvironment roundEnvironment,
139                 ProcessingEnvironment processingEnvironment,
140                 BindingBuildInfo buildInfo) {
141             if (mDone) {
142                 return true;
143             }
144             mDone = onHandleStep(roundEnvironment, processingEnvironment, buildInfo);
145             return mDone;
146         }
147 
148         /**
149          * Invoked in each annotation processing step.
150          *
151          * @return True if it is done and should never be invoked again.
152          */
onHandleStep(RoundEnvironment roundEnvironment, ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo)153         abstract public boolean onHandleStep(RoundEnvironment roundEnvironment,
154                 ProcessingEnvironment processingEnvironment,
155                 BindingBuildInfo buildInfo);
156 
157         /**
158          * Invoked when processing is done. A good place to generate the output if the
159          * processor requires multiple steps.
160          */
onProcessingOver(RoundEnvironment roundEnvironment, ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo)161         abstract public void onProcessingOver(RoundEnvironment roundEnvironment,
162                 ProcessingEnvironment processingEnvironment,
163                 BindingBuildInfo buildInfo);
164     }
165 
166     interface Callback {
onChefReady(CompilerChef chef, boolean libraryProject, int minSdk)167         void onChefReady(CompilerChef chef, boolean libraryProject, int minSdk);
onBrWriterReady(BRWriter brWriter)168         void onBrWriterReady(BRWriter brWriter);
169     }
170 }
171