summaryrefslogtreecommitdiff
path: root/compiler/src/main/java/com/android/databinding
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/src/main/java/com/android/databinding')
-rw-r--r--compiler/src/main/java/com/android/databinding/LayoutBinder.java8
-rw-r--r--compiler/src/main/java/com/android/databinding/LayoutXmlProcessor.java143
-rw-r--r--compiler/src/main/java/com/android/databinding/reflection/ModelAnalyzer.java2
-rw-r--r--compiler/src/main/java/com/android/databinding/reflection/annotation/AnnotationAnalyzer.java15
-rw-r--r--compiler/src/main/java/com/android/databinding/store/LayoutFileParser.java2
-rw-r--r--compiler/src/main/java/com/android/databinding/store/ResourceBundle.java67
-rw-r--r--compiler/src/main/java/com/android/databinding/store/SetterStore.java116
-rw-r--r--compiler/src/main/java/com/android/databinding/util/GenerationalClassUtil.java187
-rw-r--r--compiler/src/main/java/com/android/databinding/writer/AnnotationJavaFileWriter.java12
-rw-r--r--compiler/src/main/java/com/android/databinding/writer/JavaFileWriter.java21
10 files changed, 403 insertions, 170 deletions
diff --git a/compiler/src/main/java/com/android/databinding/LayoutBinder.java b/compiler/src/main/java/com/android/databinding/LayoutBinder.java
index a285e165..a2aa2485 100644
--- a/compiler/src/main/java/com/android/databinding/LayoutBinder.java
+++ b/compiler/src/main/java/com/android/databinding/LayoutBinder.java
@@ -43,6 +43,7 @@ public class LayoutBinder {
private final ExpressionParser mExpressionParser;
private final List<BindingTarget> mBindingTargets;
private String mPackage;
+ private String mModulePackage;
private String mProjectPackage;
private String mBaseClassName;
private final HashMap<String, String> mUserDefinedVariables = new HashMap<String, String>();
@@ -57,7 +58,8 @@ public class LayoutBinder {
mBindingTargets = new ArrayList<BindingTarget>();
mBundle = layoutBundle;
mProjectPackage = resourceBundle.getAppPackage();
- mPackage = mProjectPackage + ".generated";
+ mModulePackage = layoutBundle.getModulePackage();
+ mPackage = layoutBundle.getModulePackage() + ".generated";
mBaseClassName = ParserHelper.INSTANCE$.toClassName(layoutBundle.getFileName()) + "Binding";
// copy over data.
for (Map.Entry<String, String> variable : mBundle.getVariables().entrySet()) {
@@ -159,6 +161,10 @@ public class LayoutBinder {
return mPackage;
}
+ public String getModulePackage() {
+ return mModulePackage;
+ }
+
public void setPackage(String aPackage) {
mPackage = aPackage;
}
diff --git a/compiler/src/main/java/com/android/databinding/LayoutXmlProcessor.java b/compiler/src/main/java/com/android/databinding/LayoutXmlProcessor.java
index ed170bff..d0ce5068 100644
--- a/compiler/src/main/java/com/android/databinding/LayoutXmlProcessor.java
+++ b/compiler/src/main/java/com/android/databinding/LayoutXmlProcessor.java
@@ -20,15 +20,16 @@ import com.android.databinding.store.LayoutFileParser;
import com.android.databinding.store.ResourceBundle;
import com.android.databinding.writer.JavaFileWriter;
-import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringEscapeUtils;
import org.xml.sax.SAXException;
+import android.binding.BindingBuildInfo;
+
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.StringWriter;
-import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@@ -44,24 +45,51 @@ import javax.xml.xpath.XPathExpressionException;
* processor to work with.
*/
public class LayoutXmlProcessor {
-
- public static final String RESOURCE_BUNDLE_PACKAGE = "com.android.databinding.layouts.";
- public static final String APPLICATION_INFO_CLASS = "ApplicationBindingInfo";
+ // hardcoded in baseAdapters
+ public static final String RESOURCE_BUNDLE_PACKAGE = "com.android.databinding.layouts";
+ public static final String CLASS_NAME = "DataBindingInfo";
private final JavaFileWriter mFileWriter;
private final ResourceBundle mResourceBundle;
private final int mMinSdk;
private boolean mProcessingComplete;
private boolean mWritten;
+ private final boolean mIsLibrary;
private final String mBuildId = UUID.randomUUID().toString();
- private final List<File> mResourceFolders;
+ // can be a list of xml files or folders that contain XML files
+ private final List<File> mResources;
- public LayoutXmlProcessor(String applicationPackage, List<File> resourceFolders,
- JavaFileWriter fileWriter, int minSdk) {
+ public LayoutXmlProcessor(String applicationPackage, List<File> resources,
+ JavaFileWriter fileWriter, int minSdk, boolean isLibrary) {
mFileWriter = fileWriter;
mResourceBundle = new ResourceBundle(applicationPackage);
- mResourceFolders = resourceFolders;
+ mResources = resources;
mMinSdk = minSdk;
+ mIsLibrary = isLibrary;
+ }
+
+ public static List<File> getLayoutFiles(List<File> resources) {
+ List<File> result = new ArrayList<File>();
+ for (File resource : Iterables.filter(resources, fileExists)) {
+ if (resource.isDirectory()) {
+ for (File layoutFolder : resource.listFiles(layoutFolderFilter)) {
+ for (File xmlFile : layoutFolder.listFiles(xmlFileFilter)) {
+ result.add(xmlFile);
+ }
+
+ }
+ } else if (xmlFileFilter.accept(resource.getParentFile(), resource.getName())) {
+ result.add(resource);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * used by the studio plugin
+ */
+ public ResourceBundle getResourceBundle() {
+ return mResourceBundle;
}
public boolean processResources()
@@ -72,92 +100,101 @@ public class LayoutXmlProcessor {
}
LayoutFileParser layoutFileParser = new LayoutFileParser();
int layoutId = 0;
- for (File resFolder : Iterables.filter(mResourceFolders, fileExists)) {
- for (File layoutFolder : resFolder.listFiles(layoutFolderFilter)) {
- for (File xmlFile : layoutFolder.listFiles(xmlFileFilter)) {
- final ResourceBundle.LayoutFileBundle bindingLayout = layoutFileParser
- .parseXml(xmlFile, mResourceBundle.getAppPackage(), layoutId);
- if (bindingLayout != null && !bindingLayout.isEmpty()) {
- mResourceBundle.addLayoutBundle(bindingLayout, layoutId);
- layoutId++;
- }
- }
+ for (File xmlFile : getLayoutFiles(mResources)) {
+ final ResourceBundle.LayoutFileBundle bindingLayout = layoutFileParser
+ .parseXml(xmlFile, mResourceBundle.getAppPackage(), layoutId);
+ if (bindingLayout != null && !bindingLayout.isEmpty()) {
+ mResourceBundle.addLayoutBundle(bindingLayout, layoutId);
+ layoutId++;
}
}
mProcessingComplete = true;
return true;
}
- public ResourceBundle getResourceBundle() {
- return mResourceBundle;
- }
-
- public void writeIntermediateFile(File sdkDir) throws JAXBException {
+ public void writeIntermediateFile(File sdkDir, File xmlOutDir) throws JAXBException {
if (mWritten) {
return;
}
JAXBContext context = JAXBContext.newInstance(ResourceBundle.LayoutFileBundle.class);
Marshaller marshaller = context.createMarshaller();
- writeAppInfo(marshaller, sdkDir);
+ writeInfoClass(marshaller, sdkDir, xmlOutDir);
for (List<ResourceBundle.LayoutFileBundle> layouts : mResourceBundle.getLayoutBundles()
.values()) {
for (ResourceBundle.LayoutFileBundle layout : layouts) {
- writeAnnotatedFile(layout, marshaller);
+ writeXmlFile(xmlOutDir, layout, marshaller);
}
}
mWritten = true;
}
- private void writeAnnotatedFile(ResourceBundle.LayoutFileBundle layout, Marshaller marshaller)
+ private void writeXmlFile(File xmlOutDir, ResourceBundle.LayoutFileBundle layout,
+ Marshaller marshaller) throws JAXBException {
+ String filename = generateExportFileName(layout) + ".xml";
+ String xml = toXML(layout, marshaller);
+ mFileWriter.writeToFile(new File(xmlOutDir, filename), xml);
+ }
+
+ public String getInfoClassFullName() {
+ return RESOURCE_BUNDLE_PACKAGE + "." + CLASS_NAME;
+ }
+
+ private String toXML(ResourceBundle.LayoutFileBundle layout, Marshaller marshaller)
throws JAXBException {
- StringBuilder className = new StringBuilder(layout.getFileName());
- className.append('-').append(layout.getDirectory());
- for (int i = className.length() - 1; i >= 0; i--) {
- char c = className.charAt(i);
+ StringWriter writer = new StringWriter();
+ marshaller.marshal(layout, writer);
+ return writer.getBuffer().toString();
+ }
+
+ /**
+ * Generates a string identifier that can uniquely identify the given layout bundle.
+ * This identifier can be used when we need to export data about this layout bundle.
+ */
+ private String generateExportFileName(ResourceBundle.LayoutFileBundle layout) {
+ StringBuilder name = new StringBuilder(layout.getFileName());
+ name.append('-').append(layout.getDirectory());
+ for (int i = name.length() - 1; i >= 0; i--) {
+ char c = name.charAt(i);
if (c == '-') {
- className.deleteCharAt(i);
- c = Character.toUpperCase(className.charAt(i));
- className.setCharAt(i, c);
+ name.deleteCharAt(i);
+ c = Character.toUpperCase(name.charAt(i));
+ name.setCharAt(i, c);
}
}
- className.setCharAt(0, Character.toUpperCase(className.charAt(0)));
- StringWriter writer = new StringWriter();
- marshaller.marshal(layout, writer);
- String xml = writer.getBuffer().toString();
- String classString = "import android.binding.BinderBundle;\n\n" +
- "@BinderBundle(\"" +
- Base64.encodeBase64String(xml.getBytes(StandardCharsets.UTF_8)) +
- "\")\n" +
- "public class " + className + " {}\n";
- mFileWriter.writeToFile(RESOURCE_BUNDLE_PACKAGE + className, classString);
+ return name.toString();
}
- private void writeAppInfo(Marshaller marshaller, File sdkDir) {
+ private void writeInfoClass(Marshaller marshaller, File sdkDir, File xmlOutDir) {
final String sdkPath = StringEscapeUtils.escapeJava(sdkDir.getAbsolutePath());
- String classString = "import android.binding.BindingAppInfo;\n\n" +
- "@BindingAppInfo(buildId=\"" + mBuildId + "\", " +
- "applicationPackage=\"" + mResourceBundle.getAppPackage() + "\", " +
+ final Class annotation = BindingBuildInfo.class;
+ final String layoutInfoPath = StringEscapeUtils.escapeJava(xmlOutDir.getAbsolutePath());
+ String classString = "package " + RESOURCE_BUNDLE_PACKAGE + ";\n\n" +
+ "import " + annotation.getCanonicalName() + ";\n\n" +
+ "@" + annotation.getSimpleName() + "(buildId=\"" + mBuildId + "\", " +
+ "modulePackage=\"" + mResourceBundle.getAppPackage() + "\", " +
"sdkRoot=\"" + sdkPath + "\", " +
+ "layoutInfoDir=\"" + layoutInfoPath + "\"," +
+ "isLibrary=" + mIsLibrary + "," +
"minSdk=" + mMinSdk + ")\n" +
- "public class " + APPLICATION_INFO_CLASS + " {}\n";
- mFileWriter.writeToFile(RESOURCE_BUNDLE_PACKAGE + APPLICATION_INFO_CLASS, classString);
+ "public class " + CLASS_NAME + " {}\n";
+ mFileWriter.writeToFile(mResourceBundle.getAppPackage() + "." + CLASS_NAME, classString);
}
- private final Predicate<File> fileExists = new Predicate<File>() {
+ private static final Predicate<File> fileExists = new Predicate<File>() {
@Override
public boolean apply(File input) {
return input.exists() && input.canRead();
}
};
- private final FilenameFilter layoutFolderFilter = new FilenameFilter() {
+ private static final FilenameFilter layoutFolderFilter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.startsWith("layout");
}
};
- private final FilenameFilter xmlFileFilter = new FilenameFilter() {
+ private static final FilenameFilter xmlFileFilter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".xml");
diff --git a/compiler/src/main/java/com/android/databinding/reflection/ModelAnalyzer.java b/compiler/src/main/java/com/android/databinding/reflection/ModelAnalyzer.java
index 63cbc38b..9a7ef2f4 100644
--- a/compiler/src/main/java/com/android/databinding/reflection/ModelAnalyzer.java
+++ b/compiler/src/main/java/com/android/databinding/reflection/ModelAnalyzer.java
@@ -209,8 +209,6 @@ public abstract class ModelAnalyzer {
public abstract ModelClass findClass(String className, Map<String, String> imports);
- public abstract List<URL> getResources(String name);
-
public abstract ModelClass findClass(Class classType);
public abstract TypeUtil createTypeUtil();
diff --git a/compiler/src/main/java/com/android/databinding/reflection/annotation/AnnotationAnalyzer.java b/compiler/src/main/java/com/android/databinding/reflection/annotation/AnnotationAnalyzer.java
index ca40f2e8..92c6aa8c 100644
--- a/compiler/src/main/java/com/android/databinding/reflection/annotation/AnnotationAnalyzer.java
+++ b/compiler/src/main/java/com/android/databinding/reflection/annotation/AnnotationAnalyzer.java
@@ -439,21 +439,6 @@ public class AnnotationAnalyzer extends ModelAnalyzer {
}
@Override
- public List<URL> getResources(String name) {
- ArrayList<URL> urls = new ArrayList<URL>();
- try {
- Enumeration<URL> resources = getClass().getClassLoader().getResources(name);
- while (resources.hasMoreElements()) {
- urls.add(resources.nextElement());
- }
- } catch (IOException e) {
- L.e(e, "IOException while getting resources:");
- }
-
- return urls;
- }
-
- @Override
public ModelClass findClass(Class classType) {
return findClass(classType.getCanonicalName(), null);
}
diff --git a/compiler/src/main/java/com/android/databinding/store/LayoutFileParser.java b/compiler/src/main/java/com/android/databinding/store/LayoutFileParser.java
index 752562ba..99efe6ba 100644
--- a/compiler/src/main/java/com/android/databinding/store/LayoutFileParser.java
+++ b/compiler/src/main/java/com/android/databinding/store/LayoutFileParser.java
@@ -67,7 +67,7 @@ public class LayoutFileParser {
ResourceBundle.LayoutFileBundle bundle = new ResourceBundle.LayoutFileBundle(
ParserHelper.INSTANCE$.stripExtension(xml.getName()), layoutId,
- xml.getParentFile().getName());
+ xml.getParentFile().getName(), pkg);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
final DocumentBuilder builder = factory.newDocumentBuilder();
diff --git a/compiler/src/main/java/com/android/databinding/store/ResourceBundle.java b/compiler/src/main/java/com/android/databinding/store/ResourceBundle.java
index 767cc34e..a781417b 100644
--- a/compiler/src/main/java/com/android/databinding/store/ResourceBundle.java
+++ b/compiler/src/main/java/com/android/databinding/store/ResourceBundle.java
@@ -57,7 +57,15 @@ public class ResourceBundle implements Serializable {
mLayoutBundles.put(bundle.mFileName, new ArrayList<LayoutFileBundle>());
}
bundle.mLayoutId = layoutId;
- mLayoutBundles.get(bundle.mFileName).add(bundle);
+ final List<LayoutFileBundle> bundles = mLayoutBundles.get(bundle.mFileName);
+ for (LayoutFileBundle existing : bundles) {
+ if (existing.equals(bundle)) {
+ L.d("skipping layout bundle %s because it already exists.", bundle);
+ return;
+ }
+ }
+ L.d("adding bundle %s", bundle);
+ bundles.add(bundle);
}
public HashMap<String, List<LayoutFileBundle>> getLayoutBundles() {
@@ -200,6 +208,8 @@ public class ResourceBundle implements Serializable {
public int mLayoutId;
@XmlAttribute(name="layout", required = true)
public String mFileName;
+ @XmlAttribute(name="modulePackage", required = true)
+ public String mModulePackage;
private String mConfigName;
@XmlAttribute(name="directory", required = true)
@@ -222,10 +232,12 @@ public class ResourceBundle implements Serializable {
public LayoutFileBundle() {
}
- public LayoutFileBundle(String fileName, int layoutId, String directory) {
+ public LayoutFileBundle(String fileName, int layoutId, String directory,
+ String modulePackage) {
mFileName = fileName;
mLayoutId = layoutId;
mDirectory = directory;
+ mModulePackage = modulePackage;
}
public void addVariable(String name, String type) {
@@ -288,6 +300,57 @@ public class ResourceBundle implements Serializable {
public List<BindingTargetBundle> getBindingTargetBundles() {
return mBindingTargetBundles;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ LayoutFileBundle bundle = (LayoutFileBundle) o;
+
+ if (mConfigName != null ? !mConfigName.equals(bundle.mConfigName)
+ : bundle.mConfigName != null) {
+ return false;
+ }
+ if (mDirectory != null ? !mDirectory.equals(bundle.mDirectory)
+ : bundle.mDirectory != null) {
+ return false;
+ }
+ if (mFileName != null ? !mFileName.equals(bundle.mFileName)
+ : bundle.mFileName != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mFileName != null ? mFileName.hashCode() : 0;
+ result = 31 * result + (mConfigName != null ? mConfigName.hashCode() : 0);
+ result = 31 * result + (mDirectory != null ? mDirectory.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "LayoutFileBundle{" +
+ "mHasVariations=" + mHasVariations +
+ ", mDirectory='" + mDirectory + '\'' +
+ ", mConfigName='" + mConfigName + '\'' +
+ ", mModulePackage='" + mModulePackage + '\'' +
+ ", mFileName='" + mFileName + '\'' +
+ ", mLayoutId=" + mLayoutId +
+ '}';
+ }
+
+ public String getModulePackage() {
+ return mModulePackage;
+ }
}
@XmlAccessorType(XmlAccessType.NONE)
diff --git a/compiler/src/main/java/com/android/databinding/store/SetterStore.java b/compiler/src/main/java/com/android/databinding/store/SetterStore.java
index fe14b7e5..a34c8c58 100644
--- a/compiler/src/main/java/com/android/databinding/store/SetterStore.java
+++ b/compiler/src/main/java/com/android/databinding/store/SetterStore.java
@@ -18,6 +18,7 @@ package com.android.databinding.store;
import com.android.databinding.reflection.ModelAnalyzer;
import com.android.databinding.reflection.ModelClass;
import com.android.databinding.reflection.ModelMethod;
+import com.android.databinding.util.GenerationalClassUtil;
import com.android.databinding.util.L;
import org.apache.commons.lang3.StringUtils;
@@ -30,6 +31,7 @@ import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -50,7 +52,7 @@ import javax.tools.StandardLocation;
public class SetterStore {
- public static final String SETTER_STORE_FILE_NAME = "setter_store.bin";
+ public static final String SETTER_STORE_FILE_EXT = "-setter_store.bin";
private static SetterStore sStore;
@@ -62,70 +64,24 @@ public class SetterStore {
mStore = store;
}
- public static SetterStore get(ProcessingEnvironment processingEnvironment) {
- if (sStore == null) {
- InputStream in = null;
- try {
- Filer filer = processingEnvironment.getFiler();
- FileObject resource = filer.getResource(StandardLocation.CLASS_OUTPUT,
- SetterStore.class.getPackage().getName(), SETTER_STORE_FILE_NAME);
- if (resource != null && new File(resource.getName()).exists()) {
- in = resource.openInputStream();
- if (in != null) {
- sStore = load(in);
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- if (sStore == null) {
- sStore = new SetterStore(null, new IntermediateV1());
- }
- }
- return sStore;
- }
-
public static SetterStore get(ModelAnalyzer modelAnalyzer) {
if (sStore == null) {
- sStore = load(modelAnalyzer);
+ sStore = load(modelAnalyzer, SetterStore.class.getClassLoader());
}
return sStore;
}
- private static SetterStore load(ModelAnalyzer modelAnalyzer) {
+ private static SetterStore load(ModelAnalyzer modelAnalyzer, ClassLoader classLoader) {
IntermediateV1 store = new IntermediateV1();
- String resourceName = SetterStore.class.getPackage().getName().replace('.', '/') +
- '/' + SETTER_STORE_FILE_NAME;
- try {
- for (URL resource : modelAnalyzer.getResources(resourceName)) {
- merge(store, resource);
- }
- return new SetterStore(modelAnalyzer, store);
- } catch (IOException e) {
- L.e(e, "Could not read SetterStore intermediate file");
- } catch (ClassNotFoundException e) {
- L.e(e, "Could not read SetterStore intermediate file");
+ List<Intermediate> previousStores = GenerationalClassUtil
+ .loadObjects(classLoader,
+ new GenerationalClassUtil.ExtensionFilter(SETTER_STORE_FILE_EXT));
+ for (Intermediate intermediate : previousStores) {
+ merge(store, intermediate);
}
return new SetterStore(modelAnalyzer, store);
}
- private static SetterStore load(InputStream inputStream)
- throws IOException, ClassNotFoundException {
- ObjectInputStream in = new ObjectInputStream(inputStream);
- Intermediate intermediate = (Intermediate) in.readObject();
- return new SetterStore(null, (IntermediateV1) intermediate.upgrade());
- }
-
public void addRenamedMethod(String attribute, String declaringClass, String method,
TypeElement declaredOn) {
HashMap<String, MethodDescription> renamed = mStore.renamedMethods.get(attribute);
@@ -135,10 +91,12 @@ public class SetterStore {
}
MethodDescription methodDescription =
new MethodDescription(declaredOn.getQualifiedName().toString(), method);
+ L.d("STORE addmethod desc %s", methodDescription);
renamed.put(declaringClass, methodDescription);
}
public void addBindingAdapter(String attribute, ExecutableElement bindingMethod) {
+ L.d("STORE addBindingAdapter %s %s", attribute, bindingMethod);
HashMap<AccessorKey, MethodDescription> adapters = mStore.adapterMethods.get(attribute);
if (adapters == null) {
@@ -158,6 +116,7 @@ public class SetterStore {
}
public void addUntaggableTypes(String[] typeNames, TypeElement declaredOn) {
+ L.d("STORE addUntaggableTypes %s %s", Arrays.toString(typeNames), declaredOn);
String declaredType = declaredOn.getQualifiedName().toString();
for (String type : typeNames) {
mStore.untaggableTypes.put(type, declaredType);
@@ -187,6 +146,7 @@ public class SetterStore {
}
public void addConversionMethod(ExecutableElement conversionMethod) {
+ L.d("STORE addConversionMethod %s", conversionMethod);
List<? extends VariableElement> parameters = conversionMethod.getParameters();
String fromType = getQualifiedName(parameters.get(0).asType());
String toType = getQualifiedName(conversionMethod.getReturnType());
@@ -248,21 +208,10 @@ public class SetterStore {
keys.clear();
}
- public void write(ProcessingEnvironment processingEnvironment) throws IOException {
- Filer filer = processingEnvironment.getFiler();
- FileObject resource = filer.createResource(StandardLocation.CLASS_OUTPUT,
- SetterStore.class.getPackage().getName(), "setter_store.bin");
- L.d("============= Writing intermediate file: %s", resource.getName());
- ObjectOutputStream out = null;
- try {
- out = new ObjectOutputStream(resource.openOutputStream());
-
- out.writeObject(mStore);
- } finally {
- if (out != null) {
- out.close();
- }
- }
+ public void write(String projectPackage, ProcessingEnvironment processingEnvironment)
+ throws IOException {
+ GenerationalClassUtil.writeIntermediateFile(processingEnvironment,
+ projectPackage, projectPackage + SETTER_STORE_FILE_EXT, mStore);
}
public SetterCall getSetterCall(String attribute, ModelClass viewType,
@@ -503,27 +452,12 @@ public class SetterStore {
}
}
- private static void merge(IntermediateV1 store,
- URL nextUrl) throws IOException, ClassNotFoundException {
- InputStream inputStream = null;
- JarFile jarFile = null;
- try {
- inputStream = nextUrl.openStream();
- ObjectInputStream in = new ObjectInputStream(inputStream);
- Intermediate intermediate = (Intermediate) in.readObject();
- IntermediateV1 intermediateV1 = (IntermediateV1) intermediate.upgrade();
- merge(store.adapterMethods, intermediateV1.adapterMethods);
- merge(store.renamedMethods, intermediateV1.renamedMethods);
- merge(store.conversionMethods, intermediateV1.conversionMethods);
- store.untaggableTypes.putAll(intermediateV1.untaggableTypes);
- } finally {
- if (inputStream != null) {
- inputStream.close();
- }
- if (jarFile != null) {
- jarFile.close();
- }
- }
+ private static void merge(IntermediateV1 store, Intermediate dumpStore) {
+ IntermediateV1 intermediateV1 = (IntermediateV1) dumpStore.upgrade();
+ merge(store.adapterMethods, intermediateV1.adapterMethods);
+ merge(store.renamedMethods, intermediateV1.renamedMethods);
+ merge(store.conversionMethods, intermediateV1.conversionMethods);
+ store.untaggableTypes.putAll(intermediateV1.untaggableTypes);
}
private static <K, V> void merge(HashMap<K, HashMap<V, MethodDescription>> first,
@@ -619,7 +553,7 @@ public class SetterStore {
}
}
- private interface Intermediate {
+ private interface Intermediate extends Serializable {
Intermediate upgrade();
}
diff --git a/compiler/src/main/java/com/android/databinding/util/GenerationalClassUtil.java b/compiler/src/main/java/com/android/databinding/util/GenerationalClassUtil.java
new file mode 100644
index 00000000..c970ad53
--- /dev/null
+++ b/compiler/src/main/java/com/android/databinding/util/GenerationalClassUtil.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2015 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 com.android.databinding.util;
+
+import com.android.databinding.util.L;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.filefilter.IOFileFilter;
+import org.apache.commons.io.filefilter.TrueFileFilter;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.tools.FileObject;
+import javax.tools.StandardLocation;
+
+/**
+ * A utility class that helps adding build specific objects to the jar file
+ * and their extraction later on.
+ */
+public class GenerationalClassUtil {
+ public static <T extends Serializable> List<T> loadObjects(ClassLoader classLoader, Filter filter) {
+ final List<T> result = new ArrayList<T>();
+ if (!(classLoader instanceof URLClassLoader)) {
+ L.d("class loader is not url class loader (%s). skipping.", classLoader.getClass());
+ return result;
+ }
+ final URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
+ for (URL url : urlClassLoader.getURLs()) {
+ L.d("checking url %s for intermediate data", url);
+ try {
+ final File file = new File(url.toURI());
+ if (!file.exists()) {
+ L.d("cannot load file for %s", url);
+ continue;
+ }
+ if (file.isDirectory()) {
+ // probably exported classes dir.
+ loadFromDirectory(filter, result, file);
+ } else {
+ // assume it is a zip file
+ loadFomZipFile(filter, result, file);
+ }
+ } catch (IOException e) {
+ L.d("cannot open zip file from %s", url);
+ } catch (URISyntaxException e) {
+ L.d("cannot open zip file from %s", url);
+ }
+ }
+ return result;
+ }
+
+ private static <T extends Serializable> void loadFromDirectory(final Filter filter, List<T> result,
+ File directory) {
+ //noinspection unchecked
+ Collection<File> files = FileUtils.listFiles(directory, new IOFileFilter() {
+ @Override
+ public boolean accept(File file) {
+ return filter.accept(file.getName());
+ }
+
+ @Override
+ public boolean accept(File dir, String name) {
+ return filter.accept(name);
+ }
+ }, TrueFileFilter.INSTANCE);
+ for (File file : files) {
+ InputStream inputStream = null;
+ try {
+ inputStream = FileUtils.openInputStream(file);
+ T item = fromInputStream(result, inputStream);
+ L.d("loaded item %s from file", item);
+ if (item != null) {
+ result.add(item);
+ }
+ } catch (IOException e) {
+ L.e(e, "Could not merge in Bindables from %s", file.getAbsolutePath());
+ } catch (ClassNotFoundException e) {
+ L.e(e, "Could not read Binding properties intermediate file. %s", file.getAbsolutePath());
+ } finally {
+ IOUtils.closeQuietly(inputStream);
+ }
+ }
+ }
+
+ private static <T extends Serializable> void loadFomZipFile(Filter filter,
+ List<T> result, File file) throws IOException {
+ ZipFile zipFile = new ZipFile(file);
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ if (!filter.accept(entry.getName())) {
+ continue;
+ }
+ L.d("loading data from file %s", entry.getName());
+ InputStream inputStream = null;
+ try {
+ inputStream = zipFile.getInputStream(entry);
+ T item = fromInputStream(result, inputStream);
+ L.d("loaded item %s from zip file", item);
+ if (item != null) {
+ result.add(item);
+ }
+ } catch (IOException e) {
+ L.e(e, "Could not merge in Bindables from %s", file.getAbsolutePath());
+ } catch (ClassNotFoundException e) {
+ L.e(e, "Could not read Binding properties intermediate file. %s", file.getAbsolutePath());
+ } finally {
+ IOUtils.closeQuietly(inputStream);
+ }
+ }
+ }
+
+ private static <T extends Serializable> T fromInputStream(List<T> result,
+ InputStream inputStream) throws IOException, ClassNotFoundException {
+ ObjectInputStream in = new ObjectInputStream(inputStream);
+ return (T) in.readObject();
+
+ }
+
+ public static void writeIntermediateFile(ProcessingEnvironment processingEnv,
+ String packageName, String fileName, Serializable object) {
+ ObjectOutputStream oos = null;
+ try {
+ FileObject intermediate = processingEnv.getFiler().createResource(
+ StandardLocation.CLASS_OUTPUT, packageName,
+ fileName);
+ OutputStream ios = intermediate.openOutputStream();
+ oos = new ObjectOutputStream(ios);
+ oos.writeObject(object);
+ oos.close();
+ L.d("wrote intermediate bindable file %s %s", packageName, fileName);
+ } catch (IOException e) {
+ L.e(e, "Could not write to intermediate file: %s", fileName);
+ } finally {
+ IOUtils.closeQuietly(oos);
+ }
+ }
+
+
+ public static interface Filter {
+ public boolean accept(String entryName);
+ }
+
+ public static class ExtensionFilter implements Filter {
+ private final String mExtension;
+ public ExtensionFilter(String extension) {
+ mExtension = extension;
+ }
+
+ @Override
+ public boolean accept(String entryName) {
+ return entryName.endsWith(mExtension);
+ }
+ }
+}
diff --git a/compiler/src/main/java/com/android/databinding/writer/AnnotationJavaFileWriter.java b/compiler/src/main/java/com/android/databinding/writer/AnnotationJavaFileWriter.java
index 67d274ed..d24ac04a 100644
--- a/compiler/src/main/java/com/android/databinding/writer/AnnotationJavaFileWriter.java
+++ b/compiler/src/main/java/com/android/databinding/writer/AnnotationJavaFileWriter.java
@@ -15,8 +15,14 @@
*/
package com.android.databinding.writer;
+import com.google.common.base.Preconditions;
+
+import com.android.databinding.util.L;
+
+import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
+import java.io.File;
import java.io.IOException;
import java.io.Writer;
@@ -24,7 +30,7 @@ import javax.annotation.processing.ProcessingEnvironment;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
-public class AnnotationJavaFileWriter implements JavaFileWriter {
+public class AnnotationJavaFileWriter extends JavaFileWriter {
private final ProcessingEnvironment mProcessingEnvironment;
public AnnotationJavaFileWriter(ProcessingEnvironment processingEnvironment) {
@@ -35,13 +41,13 @@ public class AnnotationJavaFileWriter implements JavaFileWriter {
public void writeToFile(String canonicalName, String contents) {
Writer writer = null;
try {
+ L.d("writing file %s", canonicalName);
JavaFileObject javaFileObject =
mProcessingEnvironment.getFiler().createSourceFile(canonicalName);
writer = javaFileObject.openWriter();
writer.write(contents);
} catch (IOException e) {
- mProcessingEnvironment.getMessager().printMessage(Diagnostic.Kind.ERROR,
- "Could not write to " + canonicalName + ": " + e.getLocalizedMessage());
+ L.e(e, "Could not write to %s", canonicalName);
} finally {
if (writer != null) {
IOUtils.closeQuietly(writer);
diff --git a/compiler/src/main/java/com/android/databinding/writer/JavaFileWriter.java b/compiler/src/main/java/com/android/databinding/writer/JavaFileWriter.java
index f7b3c9ce..9fa93477 100644
--- a/compiler/src/main/java/com/android/databinding/writer/JavaFileWriter.java
+++ b/compiler/src/main/java/com/android/databinding/writer/JavaFileWriter.java
@@ -13,6 +13,23 @@
package com.android.databinding.writer;
-public interface JavaFileWriter {
- public void writeToFile(String canonicalName, String contents);
+import com.android.databinding.util.L;
+
+import org.apache.commons.io.FileUtils;
+
+import java.io.File;
+import java.io.IOException;
+
+public abstract class JavaFileWriter {
+ public abstract void writeToFile(String canonicalName, String contents);
+ public void writeToFile(File exactPath, String contents) {
+ File parent = exactPath.getParentFile();
+ parent.mkdirs();
+ try {
+ L.d("writing file %s", exactPath.getAbsoluteFile());
+ FileUtils.writeStringToFile(exactPath, contents);
+ } catch (IOException e) {
+ L.e(e, "Could not write to %s", exactPath);
+ }
+ }
}