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