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