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