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