summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java7
-rw-r--r--compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java48
-rw-r--r--compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressionsFromV1Compat.kt110
-rw-r--r--compiler/src/main/java/android/databinding/tool/CompilerChef.java57
-rw-r--r--compiler/src/main/java/android/databinding/tool/util/GenerationalClassUtil.java8
-rw-r--r--compiler/src/main/kotlin/android/databinding/tool/writer/BindingMapperWriter.kt6
-rw-r--r--compiler/src/main/kotlin/android/databinding/tool/writer/BindingMapperWriterV2.kt3
-rw-r--r--compiler/src/main/kotlin/android/databinding/tool/writer/MergedBindingMapperWriter.kt13
8 files changed, 223 insertions, 29 deletions
diff --git a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java
index 7252dcbf..8382d127 100644
--- a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java
+++ b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java
@@ -73,7 +73,7 @@ public class ProcessDataBinding extends AbstractProcessor {
private boolean doProcess(RoundEnvironment roundEnv) {
if (mProcessingSteps == null) {
readArguments();
- initProcessingSteps();
+ initProcessingSteps(processingEnv);
}
if (mCompilerArgs == null) {
return false;
@@ -108,7 +108,7 @@ public class ProcessDataBinding extends AbstractProcessor {
return SourceVersion.latest();
}
- private void initProcessingSteps() {
+ private void initProcessingSteps(ProcessingEnvironment processingEnv) {
final ProcessBindable processBindable = new ProcessBindable();
mProcessingSteps = Arrays.asList(
new ProcessMethodAdapters(),
@@ -141,7 +141,8 @@ public class ProcessDataBinding extends AbstractProcessor {
return;
}
mWrittenMapper = true;
- mChef.writeDataBinderMapper(mCompilerArgs, mBRVariableLookup, mModulePackages);
+ mChef.writeDataBinderMapper(processingEnv, mCompilerArgs, mBRVariableLookup,
+ mModulePackages);
}
@Override
diff --git a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java
index 1006f335..d8b9bbef 100644
--- a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java
+++ b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java
@@ -17,11 +17,11 @@
package android.databinding.annotationprocessor;
import android.databinding.tool.CompilerChef;
+import android.databinding.tool.Context;
import android.databinding.tool.DataBindingCompilerArgs;
import android.databinding.tool.LayoutXmlProcessor;
import android.databinding.tool.processing.Scope;
import android.databinding.tool.processing.ScopedException;
-import android.databinding.tool.reflection.SdkUtil;
import android.databinding.tool.store.GenClassInfoLog;
import android.databinding.tool.store.ResourceBundle;
import android.databinding.tool.util.GenerationalClassUtil;
@@ -29,9 +29,13 @@ import android.databinding.tool.util.L;
import android.databinding.tool.util.LoggedErrorException;
import android.databinding.tool.util.Preconditions;
import android.databinding.tool.util.StringUtils;
+import android.databinding.tool.writer.BindingMapperWriter;
+import android.databinding.tool.writer.BindingMapperWriterV2;
+import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.FileUtils;
@@ -50,11 +54,13 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Consumer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.TypeElement;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
@@ -72,6 +78,8 @@ public class ProcessExpressions extends ProcessDataBinding.ProcessingStep {
resourceBundle = new ResourceBundle(args.getModulePackage());
final List<IntermediateV2> intermediateList;
GenClassInfoLog infoLog = null;
+ @Nullable
+ CompilerChef v1CompatChef = null;
if (args.isEnableV2()) {
try {
infoLog = ResourceBundle.loadClassInfoFromFolder(
@@ -83,6 +91,12 @@ public class ProcessExpressions extends ProcessDataBinding.ProcessingStep {
}
resourceBundle.addDependencyLayouts(infoLog);
intermediateList = Collections.emptyList();
+ v1CompatChef = new ProcessExpressionsFromV1Compat(
+ processingEnvironment,
+ args,
+ loadDependencyIntermediates(),
+ getWriter()
+ ).generate();
} else {
intermediateList = loadDependencyIntermediates();
for (Intermediate intermediate : intermediateList) {
@@ -109,7 +123,7 @@ public class ProcessExpressions extends ProcessDataBinding.ProcessingStep {
}
// generate them here so that bindable parser can read
try {
- writeResourceBundle(resourceBundle, args, infoLog);
+ writeResourceBundle(resourceBundle, args, infoLog, v1CompatChef);
} catch (Throwable t) {
L.e(t, "cannot generate view binders");
}
@@ -210,9 +224,11 @@ public class ProcessExpressions extends ProcessDataBinding.ProcessingStep {
private void writeResourceBundle(
ResourceBundle resourceBundle,
DataBindingCompilerArgs compilerArgs,
- @Nullable GenClassInfoLog classInfoLog) {
+ @Nullable GenClassInfoLog classInfoLog,
+ @NonNull CompilerChef v1CompatChef) {
final CompilerChef compilerChef = CompilerChef.createChef(resourceBundle,
getWriter(), compilerArgs);
+ compilerChef.setV1CompatChef(v1CompatChef);
compilerChef.sealModels();
// write this only if we are compiling an app or a library test app.
// even if data binding is enabled for tests, we should not re-generate this.
@@ -237,6 +253,10 @@ public class ProcessExpressions extends ProcessDataBinding.ProcessingStep {
}
if (compilerArgs.isLibrary() && !compilerArgs.isTestVariant()) {
Set<String> classNames = compilerChef.getClassesToBeStripped();
+ if (v1CompatChef != null) {
+ classNames.addAll(v1CompatChef.getClassesToBeStripped());
+ classNames.add(BindingMapperWriter.V1_COMPAT_QNAME);
+ }
String out = Joiner.on(StringUtils.LINE_SEPARATOR).join(classNames);
L.d("Writing list of classes to %s . \nList:%s",
compilerArgs.getExportClassListTo(), out);
@@ -259,8 +279,6 @@ public class ProcessExpressions extends ProcessDataBinding.ProcessingStep {
public static class IntermediateV1 implements Intermediate {
- transient Unmarshaller mUnmarshaller;
-
// name to xml content map
Map<String, String> mLayoutInfoMap = new HashMap<String, String>();
@@ -268,29 +286,31 @@ public class ProcessExpressions extends ProcessDataBinding.ProcessingStep {
public Intermediate upgrade() {
final IntermediateV2 updated = new IntermediateV2();
updated.mLayoutInfoMap = mLayoutInfoMap;
- updated.mUnmarshaller = mUnmarshaller;
return updated;
}
@Override
public void appendTo(ResourceBundle resourceBundle, boolean fromSource) throws
JAXBException {
- if (mUnmarshaller == null) {
- JAXBContext context = JAXBContext
- .newInstance(ResourceBundle.LayoutFileBundle.class);
- mUnmarshaller = context.createUnmarshaller();
- }
+ extractBundles().forEach(layoutFileBundle -> {
+ resourceBundle.addLayoutBundle(layoutFileBundle, fromSource);
+ });
+ }
+
+ public List<ResourceBundle.LayoutFileBundle> extractBundles() throws JAXBException {
+ List<ResourceBundle.LayoutFileBundle> bundles = new ArrayList<>();
for (String content : mLayoutInfoMap.values()) {
final InputStream is = IOUtils.toInputStream(content);
try {
- final ResourceBundle.LayoutFileBundle bundle
- = (ResourceBundle.LayoutFileBundle) mUnmarshaller.unmarshal(is);
- resourceBundle.addLayoutBundle(bundle, fromSource);
+ final ResourceBundle.LayoutFileBundle bundle = ResourceBundle.LayoutFileBundle
+ .fromXML(is);
+ bundles.add(bundle);
L.d("loaded layout info file %s", bundle);
} finally {
IOUtils.closeQuietly(is);
}
}
+ return bundles;
}
public void addEntry(String name, String contents) {
diff --git a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressionsFromV1Compat.kt b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressionsFromV1Compat.kt
new file mode 100644
index 00000000..4321b55a
--- /dev/null
+++ b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressionsFromV1Compat.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.databinding.annotationprocessor
+
+import android.databinding.tool.CompilerChef
+import android.databinding.tool.DataBindingCompilerArgs
+import android.databinding.tool.store.ResourceBundle
+import android.databinding.tool.writer.BindingMapperWriterV2
+import android.databinding.tool.writer.JavaFileWriter
+import java.util.HashMap
+import javax.annotation.processing.ProcessingEnvironment
+
+/**
+ * Loads intermediates from dependencies which are in V1, generates their code and creates a
+ * compiler chef specific to them. (to be able to treat them like a v2 dependency).
+ */
+class ProcessExpressionsFromV1Compat(
+ private val processingEnvironment: ProcessingEnvironment,
+ private val args : DataBindingCompilerArgs,
+ private val intermediates : List<ProcessExpressions.IntermediateV2>,
+ private val writer : JavaFileWriter) {
+ /**
+ * Returns a CompilerChef if we find V1 dependencies and generate code for them.
+ * Null if all dependencies are in v2
+ */
+ fun generate(): CompilerChef? {
+ // This is tricky:
+ // in libraries, we should generate them in a stripped way so that if same dependency
+ // shows up in 2 different path, it wont blow the final app
+ // if we are an app, we should generate it.
+ val isModuleInV2Lookup = HashMap<String, Boolean>()
+
+ fun isModuleInV2(modulePackage : String) : Boolean {
+ return isModuleInV2Lookup.getOrPut(modulePackage) {
+ val mapperClass = BindingMapperWriterV2.createMapperQName(modulePackage)
+ // check if mapper exists for it
+ val typeElement =
+ processingEnvironment.elementUtils.getTypeElement(mapperClass)
+ typeElement != null
+ }
+ }
+ // mapping from key (layoutName) to generated code QName (or base class)
+ val classMapping = mutableMapOf<String, String>()
+ val compatBundle = ResourceBundle(args.modulePackage)
+ intermediates
+ .flatMap {
+ it.extractBundles()
+ }
+ .filterNot { layoutFileBundle ->
+ isModuleInV2(layoutFileBundle.modulePackage)
+ }
+ .forEach {
+ classMapping[it.fileName] = it.fullBindingClass
+ compatBundle.addLayoutBundle(it, false)
+ }
+ return writeResourceBundle(
+ resourceBundle = compatBundle,
+ compilerArgs = args.copyAsV1(COMPAT_PACKAGE)
+ )
+ }
+
+ /**
+ * Generates the code for v1 compat, returns the newly generated CompilerChef.
+ * Returns null if we don't generate anything.
+ */
+ private fun writeResourceBundle(
+ resourceBundle: ResourceBundle,
+ compilerArgs: DataBindingCompilerArgs): CompilerChef? {
+ val compilerChef = CompilerChef.createChef(
+ resourceBundle,
+ writer, compilerArgs
+ )
+ compilerChef.sealModels()
+ // write this only if we are compiling an app or a library test app.
+ // even if data binding is enabled for tests, we should not re-generate this.
+ if (compilerChef.hasAnythingToGenerate()) {
+ if (!compilerArgs.isEnableV2) {
+ compilerChef.writeViewBinderInterfaces(compilerArgs.isLibrary
+ && !compilerArgs.isTestVariant)
+ }
+ if (compilerArgs.isApp != compilerArgs.isTestVariant
+ || compilerArgs.isEnabledForTests && !compilerArgs.isLibrary
+ || compilerArgs.isEnableV2
+ ) {
+ compilerChef.writeViewBinders(compilerArgs.minApi)
+ }
+ } else {
+ return null
+ }
+ return compilerChef
+ }
+
+ companion object {
+ const val COMPAT_PACKAGE = "android.databinding.v1Compat"
+ }
+}
diff --git a/compiler/src/main/java/android/databinding/tool/CompilerChef.java b/compiler/src/main/java/android/databinding/tool/CompilerChef.java
index b747d8b4..45638966 100644
--- a/compiler/src/main/java/android/databinding/tool/CompilerChef.java
+++ b/compiler/src/main/java/android/databinding/tool/CompilerChef.java
@@ -32,6 +32,8 @@ import android.databinding.tool.writer.BindingMapperWriterV2;
import android.databinding.tool.writer.JavaFileWriter;
import android.databinding.tool.writer.MergedBindingMapperWriter;
import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;
@@ -43,6 +45,11 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.TypeElement;
/**
* Chef class for compiler.
@@ -79,10 +86,17 @@ public class CompilerChef {
private ResourceBundle mResourceBundle;
private DataBinder mDataBinder;
private boolean mEnableV2;
+ // the compiler chef we create for V1 dependencies
+ @Nullable
+ private CompilerChef mV1CompatChef;
private CompilerChef() {
}
+ public void setV1CompatChef(CompilerChef v1CompatChef) {
+ mV1CompatChef = v1CompatChef;
+ }
+
public static CompilerChef createChef(
ResourceBundle bundle,
JavaFileWriter fileWriter,
@@ -171,6 +185,7 @@ public class CompilerChef {
}
public void writeDataBinderMapper(
+ ProcessingEnvironment processingEnv,
DataBindingCompilerArgs compilerArgs,
Map<String, Integer> brValueLookup,
List<String> modulePackages) {
@@ -186,6 +201,9 @@ public class CompilerChef {
if (generateMapper) {
writeMapperForModule(compilerArgs, brValueLookup);
}
+ if (mV1CompatChef != null) {
+ writeMapperForV1Compat(compilerArgs, brValueLookup);
+ }
// merged mapper is the one generated for the whole app that includes the mappers
// generated for individual modules.
@@ -198,7 +216,7 @@ public class CompilerChef {
generateMergedMapper = false;
}
if (generateMergedMapper) {
- writeMergedMapper(compilerArgs, modulePackages);
+ writeMergedMapper(processingEnv, compilerArgs, modulePackages);
}
} else {
final String pkg = "android.databinding";
@@ -213,17 +231,52 @@ public class CompilerChef {
}
}
+ private void writeMapperForV1Compat(
+ DataBindingCompilerArgs compilerArgs,
+ Map<String, Integer> brValueLookup) {
+ BindingMapperWriter dbr = new BindingMapperWriter(
+ BindingMapperWriter.V1_COMPAT_MAPPER_PKG,
+ BindingMapperWriter.V1_COMPAT_MAPPER_NAME,
+ mV1CompatChef.getLayoutBinders(),
+ compilerArgs);
+ mFileWriter.writeToFile(
+ BindingMapperWriter.V1_COMPAT_MAPPER_PKG + "." + dbr.getClassName(),
+ dbr.write(brValueLookup));
+ }
+
+ public List<LayoutBinder> getLayoutBinders() {
+ return mDataBinder.getLayoutBinders();
+ }
+
/**
* Writes the mapper android.databinding.DataBinderMapperImpl which is a merged mapper
* that includes all mappers from dependencies.
*/
private void writeMergedMapper(
+ ProcessingEnvironment processingEnv,
DataBindingCompilerArgs compilerArgs,
List<String> modulePackages) {
+ // figure out which mappers exists as they may not exist for v1 libs.
+ List<String> availableDependencyModules = modulePackages.stream()
+ .filter(modulePackage -> {
+ if (modulePackage.equals(compilerArgs.getModulePackage())) {
+ // mine will be generated
+ return true;
+ }
+ String mapper = BindingMapperWriterV2.createMapperQName(modulePackage);
+ TypeElement impl = processingEnv
+ .getElementUtils()
+ .getTypeElement(mapper);
+ return impl != null;
+ }).collect(Collectors.toList());
Set<String> featurePackageIds = loadFeaturePackageIds(compilerArgs);
StringBuilder sb = new StringBuilder();
MergedBindingMapperWriter mergedBindingMapperWriter =
- new MergedBindingMapperWriter(modulePackages, compilerArgs, featurePackageIds);
+ new MergedBindingMapperWriter(
+ availableDependencyModules,
+ compilerArgs,
+ featurePackageIds,
+ mV1CompatChef != null);
TypeSpec mergedMapperSpec = mergedBindingMapperWriter.write();
try {
JavaFile.builder(mergedBindingMapperWriter.getPkg(), mergedMapperSpec)
diff --git a/compiler/src/main/java/android/databinding/tool/util/GenerationalClassUtil.java b/compiler/src/main/java/android/databinding/tool/util/GenerationalClassUtil.java
index d1959bef..a87885bc 100644
--- a/compiler/src/main/java/android/databinding/tool/util/GenerationalClassUtil.java
+++ b/compiler/src/main/java/android/databinding/tool/util/GenerationalClassUtil.java
@@ -69,13 +69,7 @@ public class GenerationalClassUtil {
}
private GenerationalClassUtil(DataBindingCompilerArgs args) {
- if (args.isEnableV2()) {
- mEnabledExtensions = new ExtensionFilter[]{ExtensionFilter.BR,
- ExtensionFilter.SETTER_STORE};
- } else {
- mEnabledExtensions = new ExtensionFilter[]{ExtensionFilter.BR, ExtensionFilter.LAYOUT,
- ExtensionFilter.SETTER_STORE};
- }
+ mEnabledExtensions = ExtensionFilter.values();
if (StringUtils.isNotBlank(args.getAarOutFolder())) {
mIncrementalOutDir = new File(args.getAarOutFolder(),
DataBindingBuilder.INCREMENTAL_BIN_AAR_DIR);
diff --git a/compiler/src/main/kotlin/android/databinding/tool/writer/BindingMapperWriter.kt b/compiler/src/main/kotlin/android/databinding/tool/writer/BindingMapperWriter.kt
index 66f39e4c..70921a52 100644
--- a/compiler/src/main/kotlin/android/databinding/tool/writer/BindingMapperWriter.kt
+++ b/compiler/src/main/kotlin/android/databinding/tool/writer/BindingMapperWriter.kt
@@ -167,4 +167,10 @@ class BindingMapperWriter(var pkg : String, var className: String,
}
}
}.generate()
+
+ companion object {
+ const val V1_COMPAT_MAPPER_NAME = "V1CompatDataBinderMapperImpl"
+ const val V1_COMPAT_MAPPER_PKG = "android.databinding"
+ const val V1_COMPAT_QNAME = V1_COMPAT_MAPPER_PKG + "." + V1_COMPAT_MAPPER_NAME
+ }
}
diff --git a/compiler/src/main/kotlin/android/databinding/tool/writer/BindingMapperWriterV2.kt b/compiler/src/main/kotlin/android/databinding/tool/writer/BindingMapperWriterV2.kt
index 40deff3a..baa30b6a 100644
--- a/compiler/src/main/kotlin/android/databinding/tool/writer/BindingMapperWriterV2.kt
+++ b/compiler/src/main/kotlin/android/databinding/tool/writer/BindingMapperWriterV2.kt
@@ -65,6 +65,9 @@ class BindingMapperWriterV2(private val genClassInfoLog: GenClassInfoLog,
ClassName.get("android.util", "SparseIntArray")
private val SPARSE_ARRAY =
ClassName.get("android.util", "SparseArray")
+
+ @JvmStatic
+ fun createMapperQName(modulePackage : String) = modulePackage + "." + IMPL_CLASS_NAME
}
private val rClassMap = mutableMapOf<String, ClassName>()
diff --git a/compiler/src/main/kotlin/android/databinding/tool/writer/MergedBindingMapperWriter.kt b/compiler/src/main/kotlin/android/databinding/tool/writer/MergedBindingMapperWriter.kt
index f0d7e59b..8517c234 100644
--- a/compiler/src/main/kotlin/android/databinding/tool/writer/MergedBindingMapperWriter.kt
+++ b/compiler/src/main/kotlin/android/databinding/tool/writer/MergedBindingMapperWriter.kt
@@ -29,7 +29,8 @@ import javax.lang.model.element.Modifier
class MergedBindingMapperWriter(private val packages: List<String>,
compilerArgs: DataBindingCompilerArgs,
- private val featurePackages : Set<String>) {
+ private val featurePackages : Set<String>,
+ private val hasV1CompatMapper: Boolean) {
private val generateAsTest = compilerArgs.isTestVariant && compilerArgs.isApp
private val generateTestOverride = !generateAsTest && compilerArgs.isEnabledForTests
private val overrideField = FieldSpec.builder(BindingMapperWriterV2.DATA_BINDER_MAPPER,
@@ -38,8 +39,8 @@ class MergedBindingMapperWriter(private val packages: List<String>,
.build()
companion object {
- private val APP_CLASS_NAME = "DataBinderMapperImpl"
- private val TEST_CLASS_NAME = "Test$APP_CLASS_NAME"
+ const val APP_CLASS_NAME = "DataBinderMapperImpl"
+ private const val TEST_CLASS_NAME = "Test$APP_CLASS_NAME"
val MERGED_MAPPER_BASE: ClassName = ClassName.get(
"android.databinding",
"MergedDataBinderMapper")
@@ -59,6 +60,12 @@ class MergedBindingMapperWriter(private val packages: List<String>,
val mapper = ClassName.get(pkg, APP_CLASS_NAME)
addStatement("addMapper(new $T())", mapper)
}
+ if (hasV1CompatMapper) {
+ val compatMapper = ClassName.get(
+ BindingMapperWriter.V1_COMPAT_MAPPER_PKG,
+ BindingMapperWriter.V1_COMPAT_MAPPER_NAME)
+ addStatement("addMapper(new $T())", compatMapper)
+ }
featurePackages.forEach {
addStatement("addMapper($S)", it)
}