ProcessDataBinding.java revision bdc7aa8269502b3fc3ce73c124e4f1b2092502c9
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.annotation.processing.SupportedSourceVersion; 37import javax.lang.model.SourceVersion; 38import 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 */ 52public class ProcessDataBinding extends AbstractProcessor { 53 private List<ProcessingStep> mProcessingSteps; 54 @Override 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 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 mChef.writeDynamicUtil(); 98 } 99 100 private void considerWritingMapper() { 101 if (mLibraryProject || mChef == null || mBRWriter == null) { 102 return; 103 } 104 mChef.writeDataBinderMapper(mMinSdk, mBRWriter); 105 } 106 107 @Override 108 public void onBrWriterReady(BRWriter brWriter) { 109 Preconditions.checkNull(mBRWriter, "Cannot set br writer twice"); 110 mBRWriter = brWriter; 111 considerWritingMapper(); 112 } 113 }; 114 AnnotationJavaFileWriter javaFileWriter = new AnnotationJavaFileWriter(processingEnv); 115 for (ProcessingStep step : mProcessingSteps) { 116 step.mJavaFileWriter = javaFileWriter; 117 step.mCallback = dataBinderWriterCallback; 118 } 119 } 120 121 @Override 122 public synchronized void init(ProcessingEnvironment processingEnv) { 123 super.init(processingEnv); 124 ModelAnalyzer.setProcessingEnvironment(processingEnv); 125 } 126 127 /** 128 * To ensure execution order and binding build information, we use processing steps. 129 */ 130 public abstract static class ProcessingStep { 131 private boolean mDone; 132 private JavaFileWriter mJavaFileWriter; 133 protected Callback mCallback; 134 135 protected JavaFileWriter getWriter() { 136 return mJavaFileWriter; 137 } 138 139 private boolean runStep(RoundEnvironment roundEnvironment, 140 ProcessingEnvironment processingEnvironment, 141 BindingBuildInfo buildInfo) { 142 if (mDone) { 143 return true; 144 } 145 mDone = onHandleStep(roundEnvironment, processingEnvironment, buildInfo); 146 return mDone; 147 } 148 149 /** 150 * Invoked in each annotation processing step. 151 * 152 * @return True if it is done and should never be invoked again. 153 */ 154 abstract public boolean onHandleStep(RoundEnvironment roundEnvironment, 155 ProcessingEnvironment processingEnvironment, 156 BindingBuildInfo buildInfo); 157 158 /** 159 * Invoked when processing is done. A good place to generate the output if the 160 * processor requires multiple steps. 161 */ 162 abstract public void onProcessingOver(RoundEnvironment roundEnvironment, 163 ProcessingEnvironment processingEnvironment, 164 BindingBuildInfo buildInfo); 165 } 166 167 interface Callback { 168 void onChefReady(CompilerChef chef, boolean libraryProject, int minSdk); 169 void onBrWriterReady(BRWriter brWriter); 170 } 171} 172