Automated rollback of commit f672a31b8b19baab95373e4f2f6d110aa8b8f0fb.

*** Reason for rollback ***

Unclassified general breakages in tests. Rolling back for further investigation.

*** Original change description ***

Normalized the serialization proto to save space and allow greater versatility in storage.

RELNOTES: None
PiperOrigin-RevId: 186057879
diff --git a/src/test/java/com/google/devtools/build/android/AaptCommandBuilderTest.java b/src/test/java/com/google/devtools/build/android/AaptCommandBuilderTest.java
index 3ff5187..319fa48 100644
--- a/src/test/java/com/google/devtools/build/android/AaptCommandBuilderTest.java
+++ b/src/test/java/com/google/devtools/build/android/AaptCommandBuilderTest.java
@@ -111,7 +111,7 @@
 
   @Test
   public void testAddRepeatedWithEmptyValuesAddsNothing() {
-    assertThat(new AaptCommandBuilder(aapt).addRepeated("-0", ImmutableList.of()).build())
+    assertThat(new AaptCommandBuilder(aapt).addRepeated("-0", ImmutableList.<String>of()).build())
         .doesNotContain("-0");
   }
 
diff --git a/src/test/java/com/google/devtools/build/android/AndroidDataBuilder.java b/src/test/java/com/google/devtools/build/android/AndroidDataBuilder.java
index 2270ca1..5e64ef4 100644
--- a/src/test/java/com/google/devtools/build/android/AndroidDataBuilder.java
+++ b/src/test/java/com/google/devtools/build/android/AndroidDataBuilder.java
@@ -123,7 +123,7 @@
   }
 
   public AndroidDataBuilder createManifest(String path, String manifestPackage, String... lines) {
-    return createManifest(path, manifestPackage, ImmutableList.of(), lines);
+    return createManifest(path, manifestPackage, ImmutableList.<String>of(), lines);
   }
 
   public AndroidDataBuilder createManifest(
diff --git a/src/test/java/com/google/devtools/build/android/AndroidDataMergerTest.java b/src/test/java/com/google/devtools/build/android/AndroidDataMergerTest.java
index 95c9015..80bf338 100644
--- a/src/test/java/com/google/devtools/build/android/AndroidDataMergerTest.java
+++ b/src/test/java/com/google/devtools/build/android/AndroidDataMergerTest.java
@@ -61,7 +61,7 @@
   @Before
   public void setUp() throws Exception {
     fileSystem = Jimfs.newFileSystem();
-    fqnFactory = FullyQualifiedName.Factory.from(ImmutableList.of());
+    fqnFactory = FullyQualifiedName.Factory.from(ImmutableList.<String>of());
     mergerLogger = Logger.getLogger(AndroidDataMerger.class.getCanonicalName());
     loggingHandler = new TestLoggingHandler();
     mergerLogger.addHandler(loggingHandler);
diff --git a/src/test/java/com/google/devtools/build/android/AndroidDataSerializerAndDeserializerTest.java b/src/test/java/com/google/devtools/build/android/AndroidDataSerializerAndDeserializerTest.java
index 7f388c3..94529e3 100644
--- a/src/test/java/com/google/devtools/build/android/AndroidDataSerializerAndDeserializerTest.java
+++ b/src/test/java/com/google/devtools/build/android/AndroidDataSerializerAndDeserializerTest.java
@@ -47,7 +47,7 @@
   @Before
   public void createCleanEnvironment() throws Exception {
     fs = Jimfs.newFileSystem();
-    fqnFactory = FullyQualifiedName.Factory.from(ImmutableList.of());
+    fqnFactory = FullyQualifiedName.Factory.from(ImmutableList.<String>of());
     source = Files.createDirectory(fs.getPath("source"));
     manifest = Files.createFile(source.resolve("AndroidManifest.xml"));
   }
@@ -80,7 +80,8 @@
         UnwrittenMergedAndroidData.of(
             manifest,
             ParsedAndroidDataBuilder.buildOn(source, fqnFactory)
-                .combining(xml("id/snark").source("values/ids.xml").value(IdXmlResourceValue.of()))
+                .combining(
+                    xml("id/snark").source("values/ids.xml").value(IdXmlResourceValue.of()))
                 .build(),
             ParsedAndroidDataBuilder.empty());
     expected.serializeTo(serializer);
@@ -158,7 +159,10 @@
             .createManifest("AndroidManifest.xml", "com.carroll.lewis", "")
             .buildParsed();
     UnwrittenMergedAndroidData expected =
-        UnwrittenMergedAndroidData.of(manifest, direct, ParsedAndroidDataBuilder.empty());
+        UnwrittenMergedAndroidData.of(
+            manifest,
+            direct,
+            ParsedAndroidDataBuilder.empty());
     expected.serializeTo(serializer);
     serializer.flushTo(binaryPath);
 
@@ -168,8 +172,10 @@
     deserializer.read(
         binaryPath,
         KeyValueConsumers.of(
-            overwriting, combining, null // assets
-            ));
+            overwriting,
+            combining,
+            null // assets
+        ));
     Truth.assertThat(overwriting).isEqualTo(expected.getPrimary().getOverwritingResources());
     Truth.assertThat(combining).isEqualTo(expected.getPrimary().getCombiningResources());
   }
@@ -184,17 +190,17 @@
             ParsedAndroidDataBuilder.buildOn(source, fqnFactory)
                 .overwritable(
                     file("layout/banker").source("layout/banker.xml"),
-                    xml("<resources>/foo")
-                        .source("values/ids.xml")
-                        .value(
-                            ResourcesAttribute.of(
-                                fqnFactory.parse("<resources>/foo"), "foo", "fooVal")))
-                .combining(xml("id/snark").source("values/ids.xml").value(IdXmlResourceValue.of()))
+                    xml("<resources>/foo").source("values/ids.xml")
+                        .value(ResourcesAttribute.of(
+                            fqnFactory.parse("<resources>/foo"), "foo", "fooVal")))
+                .combining(
+                    xml("id/snark").source("values/ids.xml").value(IdXmlResourceValue.of()))
                 .assets(file().source("hunting/of/the/boojum"))
                 .build(),
             ParsedAndroidDataBuilder.buildOn(source, fqnFactory)
                 .overwritable(file("layout/butcher").source("layout/butcher.xml"))
-                .combining(xml("id/snark").source("values/ids.xml").value(IdXmlResourceValue.of()))
+                .combining(
+                    xml("id/snark").source("values/ids.xml").value(IdXmlResourceValue.of()))
                 .assets(file().source("hunting/of/the/snark"))
                 .build());
     expected.serializeTo(serializer);
@@ -226,43 +232,36 @@
             ParsedAndroidDataBuilder.buildOn(source, fqnFactory)
                 .overwritable(
                     file("layout/banker").source("layout/banker.xml"),
-                    xml("<resources>/foo")
-                        .source("values/res.xml")
-                        .value(
-                            ResourcesAttribute.of(
-                                fqnFactory.parse("<resources>/foo"), "foo", "fooVal")))
-                .combining(xml("id/snark").source("values/ids.xml").value(IdXmlResourceValue.of()))
+                    xml("<resources>/foo").source("values/ids.xml")
+                        .value(ResourcesAttribute.of(
+                            fqnFactory.parse("<resources>/foo"), "foo", "fooVal")))
+                .combining(
+                    xml("id/snark").source("values/ids.xml").value(IdXmlResourceValue.of()))
                 .assets(file().source("hunting/of/the/boojum"))
                 .build(),
             ParsedAndroidDataBuilder.buildOn(source, fqnFactory)
                 .overwritable(file("layout/butcher").source("layout/butcher.xml"))
-                .combining(xml("id/snark").source("values/ids.xml").value(IdXmlResourceValue.of()))
+                .combining(
+                    xml("id/snark").source("values/ids.xml").value(IdXmlResourceValue.of()))
                 .assets(file().source("hunting/of/the/snark"))
                 .build());
     expected.serializeTo(serializer);
     serializer.flushTo(binaryPath);
 
-    // Create a file to demonstrate an overmatched filtering
-    Files.createDirectories(source.resolve("res/values/ids.xml"));
-
     AndroidDataDeserializer deserializer =
         AndroidParsedDataDeserializer.withFilteredResources(
-            ImmutableList.of(
-                "the/boojum", "values/ids.xml", "layout/banker.xml", "values/res.xml"));
+            ImmutableList.of("the/boojum", "values/ids.xml", "layout/banker.xml"));
 
     KeyValueConsumers primary =
         KeyValueConsumers.of(
             TestMapConsumer.ofResources(), // overwriting
             TestMapConsumer.ofResources(), // combining
-            TestMapConsumer.ofAssets() // assets
+            null // assets
             );
 
     deserializer.read(binaryPath, primary);
     Truth.assertThat(primary.overwritingConsumer).isEqualTo(Collections.emptyMap());
-    Truth.assertThat(primary.combiningConsumer)
-        .named("Filtered resources that exist should not be filtered.")
-        .isEqualTo(expected.getPrimary().getCombiningResources());
-    Truth.assertThat(primary.assetConsumer).isEqualTo(Collections.emptyMap());
+    Truth.assertThat(primary.combiningConsumer).isEqualTo(Collections.emptyMap());
   }
 
   private static class TestMapConsumer<T extends DataValue>
diff --git a/src/test/java/com/google/devtools/build/android/AndroidResourceClassWriterTest.java b/src/test/java/com/google/devtools/build/android/AndroidResourceClassWriterTest.java
index 86d6a28..4fdaaa7 100644
--- a/src/test/java/com/google/devtools/build/android/AndroidResourceClassWriterTest.java
+++ b/src/test/java/com/google/devtools/build/android/AndroidResourceClassWriterTest.java
@@ -24,6 +24,7 @@
 import java.nio.file.FileSystem;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.List;
 import java.util.Map;
 import org.junit.Before;
 import org.junit.Rule;
@@ -44,7 +45,7 @@
   public final ExpectedException thrown = ExpectedException.none();
 
   private static final AndroidFrameworkAttrIdProvider mockAndroidFrameworkIds =
-      new MockAndroidFrameworkAttrIdProvider(ImmutableMap.of());
+      new MockAndroidFrameworkAttrIdProvider(ImmutableMap.<String, Integer>of());
 
   @Before
   public void createCleanEnvironment() {
@@ -99,13 +100,17 @@
             ImmutableMap.of(
                 "AdiosButton", 0x7f030000,
                 "HelloView", 0x7f030001),
-            ImmutableMap.of(),
-            false);
+            ImmutableMap.<String, List<Integer>>of(),
+            false
+        );
     assertAbout(paths)
         .that(target)
         .withClass("com.carroll.lewis.R$layout")
         .classContentsIsEqualTo(
-            ImmutableMap.of("some_layout", 0x7f020000), ImmutableMap.of(), false);
+            ImmutableMap.of("some_layout", 0x7f020000),
+            ImmutableMap.<String, List<Integer>>of(),
+            false
+        );
   }
 
   @Test
@@ -149,8 +154,9 @@
             ImmutableMap.of(
                 "light", 0x7f020000,
                 "patchface", 0x7f020001),
-            ImmutableMap.of(),
-            false);
+            ImmutableMap.<String, List<Integer>>of(),
+            false
+        );
   }
 
   @Test
@@ -201,8 +207,9 @@
                 "light18", 0x7f020001,
                 "light19", 0x7f020002,
                 "light20", 0x7f020003),
-            ImmutableMap.of(),
-            false);
+            ImmutableMap.<String, List<Integer>>of(),
+            false
+        );
   }
 
   @Test
@@ -307,8 +314,9 @@
                 "x_color", 0x7f010000,
                 "y_color", 0x7f010001,
                 "z_color", 0x7f010002),
-            ImmutableMap.of(),
-            false);
+            ImmutableMap.<String, List<Integer>>of(),
+            false
+        );
     assertAbout(paths)
         .that(target)
         .withClass("com.carroll.lewis.R$style")
@@ -316,8 +324,9 @@
             ImmutableMap.of(
                 "YStyle", 0x7f020000,
                 "ZStyle_ABC", 0x7f020001),
-            ImmutableMap.of(),
-            false);
+            ImmutableMap.<String, List<Integer>>of(),
+            false
+        );
     assertAbout(paths)
         .that(target)
         .withClass("com.carroll.lewis.R$styleable")
@@ -330,12 +339,14 @@
                 .put("com_google_android_Swirls_Fancy_y_color", 1)
                 .put("com_google_android_Swirls_Fancy_z_color", 2)
                 .build(),
-            ImmutableMap.of(
+            ImmutableMap.<String, List<Integer>>of(
                 "com_google_android_Dots",
                 ImmutableList.of(0x7f010000, 0x7f010001, 0x7f010002),
                 "com_google_android_Swirls_Fancy",
-                ImmutableList.of(0x7f010000, 0x7f010001, 0x7f010002)),
-            false);
+                ImmutableList.of(0x7f010000, 0x7f010001, 0x7f010002)
+            ),
+            false
+        );
   }
 
   @Test
@@ -418,12 +429,18 @@
             ImmutableMap.of(
                 "aaa", 0x7f010000,
                 "zzz", 0x7f010001),
-            ImmutableMap.of(),
-            false);
+            ImmutableMap.<String, List<Integer>>of(),
+            false
+        );
     assertAbout(paths)
         .that(target)
         .withClass("com.carroll.lewis.R$style")
-        .classContentsIsEqualTo(ImmutableMap.of("YStyle", 0x7f020000), ImmutableMap.of(), false);
+        .classContentsIsEqualTo(
+            ImmutableMap.of(
+                "YStyle", 0x7f020000),
+            ImmutableMap.<String, List<Integer>>of(),
+            false
+        );
     assertAbout(paths)
         .that(target)
         .withClass("com.carroll.lewis.R$styleable")
@@ -432,11 +449,14 @@
                 "com_google_android_Dots_android_textColor", 0,
                 "com_google_android_Dots_android_textSize", 1,
                 "com_google_android_Dots_aaa", 2,
-                "com_google_android_Dots_zzz", 3),
-            ImmutableMap.of(
+                "com_google_android_Dots_zzz", 3
+            ),
+            ImmutableMap.<String, List<Integer>>of(
                 "com_google_android_Dots",
-                ImmutableList.of(0x01000000, 0x01000010, 0x7f010000, 0x7f010001)),
-            false);
+                ImmutableList.of(0x01000000, 0x01000010, 0x7f010000, 0x7f010001)
+            ),
+            false
+        );
   }
 
   @Test
@@ -445,7 +465,9 @@
     Path source = fs.getPath("source");
     AndroidResourceClassWriter resourceClassWriter =
         AndroidResourceClassWriter.of(
-            new MockAndroidFrameworkAttrIdProvider(ImmutableMap.of()), target, "com.carroll.lewis");
+            new MockAndroidFrameworkAttrIdProvider(ImmutableMap.<String, Integer>of()),
+            target,
+            "com.carroll.lewis");
     ParsedAndroidData direct =
         AndroidDataBuilder.of(source)
             .addResource(
@@ -478,7 +500,9 @@
     Path source = fs.getPath("source");
     AndroidResourceClassWriter resourceClassWriter =
         AndroidResourceClassWriter.of(
-            new MockAndroidFrameworkAttrIdProvider(ImmutableMap.of()), target, "com.carroll.lewis");
+            new MockAndroidFrameworkAttrIdProvider(ImmutableMap.<String, Integer>of()),
+            target,
+            "com.carroll.lewis");
     ParsedAndroidData direct =
         AndroidDataBuilder.of(source)
             .addResource(
@@ -543,7 +567,11 @@
     assertAbout(paths)
         .that(target)
         .withClass("com.boop.R$drawable")
-        .classContentsIsEqualTo(ImmutableMap.of("1", 0x7f020000), ImmutableMap.of(), false);
+        .classContentsIsEqualTo(
+            ImmutableMap.of("1", 0x7f020000),
+            ImmutableMap.<String, List<Integer>>of(),
+            false
+        );
   }
 
   /**
@@ -585,7 +613,11 @@
     assertAbout(paths)
         .that(target)
         .withClass("com.boop.R$drawable")
-        .classContentsIsEqualTo(ImmutableMap.of("c++", 0x7f020000), ImmutableMap.of(), false);
+        .classContentsIsEqualTo(
+            ImmutableMap.of("c++", 0x7f020000),
+            ImmutableMap.<String, List<Integer>>of(),
+            false
+        );
   }
 
   /**
@@ -628,7 +660,11 @@
     assertAbout(paths)
         .that(target)
         .withClass("com.boop.R$integer")
-        .classContentsIsEqualTo(ImmutableMap.of("c++", 0x7f020000), ImmutableMap.of(), false);
+        .classContentsIsEqualTo(
+            ImmutableMap.of("c++", 0x7f020000),
+            ImmutableMap.<String, List<Integer>>of(),
+            false
+        );
   }
 
   private static class MockAndroidFrameworkAttrIdProvider
diff --git a/src/test/java/com/google/devtools/build/android/DataResourceXmlTest.java b/src/test/java/com/google/devtools/build/android/DataResourceXmlTest.java
index b8309e8..aa91bf9 100644
--- a/src/test/java/com/google/devtools/build/android/DataResourceXmlTest.java
+++ b/src/test/java/com/google/devtools/build/android/DataResourceXmlTest.java
@@ -77,11 +77,12 @@
   @Before
   public void createCleanEnvironment() {
     fs = Jimfs.newFileSystem();
-    fqnFactory = FullyQualifiedName.Factory.from(ImmutableList.of());
+    fqnFactory = FullyQualifiedName.Factory.from(ImmutableList.<String>of());
   }
 
   private Path writeResourceXml(String... xml) throws IOException {
-    return writeResourceXml(ImmutableMap.of(), ImmutableMap.of(), xml);
+    return writeResourceXml(ImmutableMap.<String, String>of(), ImmutableMap.<String, String>of(),
+        xml);
   }
 
   private Path writeResourceXml(Map<String, String> namespaces, Map<String, String> attributes,
@@ -756,7 +757,7 @@
         .xmlContentsIsEqualTo(
             resourcesXmlFrom(
                 XLIFF_NAMESPACES,
-                ImmutableMap.of(),
+                ImmutableMap.<String, String>of(),
                 source,
                 "<string name=\"star_rating\">Check out our 5",
                 "    <xliff:g id=\"star\">\\u2605</xliff:g>",
@@ -791,7 +792,7 @@
         .xmlContentsIsEqualTo(
             resourcesXmlFrom(
                 ImmutableMap.of("ns1", "urn:oasis:names:tc:xliff:document:1.2"),
-                ImmutableMap.of(),
+                ImmutableMap.<String, String>of(),
                 source,
                 "<string name=\"star_rating\">Check out our 5    ",
                 "<ns1:g xmlns:foglebert=\"defogle\" " + "foglebert:id=\"star\">\\u2605</ns1:g>",
@@ -829,10 +830,11 @@
       "</string>"
     };
 
-    Path source = writeResourceXml(XLIFF_NAMESPACES, ImmutableMap.of(), xml);
+    Path source = writeResourceXml(XLIFF_NAMESPACES, ImmutableMap.<String, String>of(), xml);
     assertAbout(resourcePaths)
         .that(parsedAndWritten(source, fqn("string/AAP_SUGGEST_ACCEPT_SUGGESTION")))
-        .xmlContentsIsEqualTo(resourcesXmlFrom(XLIFF_NAMESPACES, ImmutableMap.of(), source, xml));
+        .xmlContentsIsEqualTo(
+            resourcesXmlFrom(XLIFF_NAMESPACES, ImmutableMap.<String, String>of(), source, xml));
   }
 
   @Test
@@ -1272,7 +1274,8 @@
   }
 
   private String[] resourcesXmlFrom(Path source, String... lines) {
-    return resourcesXmlFrom(ImmutableMap.of(), ImmutableMap.of(), source, lines);
+    return resourcesXmlFrom(ImmutableMap.<String, String>of(), ImmutableMap.<String, String>of(),
+        source, lines);
   }
 
   private String[] resourcesXmlFrom(Map<String, String> namespaces, Map<String, String> attributes,
diff --git a/src/test/java/com/google/devtools/build/android/DensitySpecificManifestProcessorTest.java b/src/test/java/com/google/devtools/build/android/DensitySpecificManifestProcessorTest.java
index 96fa095..e43cc9f 100644
--- a/src/test/java/com/google/devtools/build/android/DensitySpecificManifestProcessorTest.java
+++ b/src/test/java/com/google/devtools/build/android/DensitySpecificManifestProcessorTest.java
@@ -54,10 +54,8 @@
         "<manifest xmlns:android='http://schemas.android.com/apk/res/android'",
         "          package='com.google.test'>",
         "</manifest>");
-    Path modified =
-        new DensitySpecificManifestProcessor(
-                ImmutableList.of(), tmp.resolve("manifest-filtered/AndroidManifest.xml"))
-            .process(manifest);
+    Path modified = new DensitySpecificManifestProcessor(ImmutableList.<String>of(),
+        tmp.resolve("manifest-filtered/AndroidManifest.xml")).process(manifest);
     assertThat((Object) modified).isEqualTo(manifest);
   }
 
@@ -142,7 +140,7 @@
     Path modified = new DensitySpecificManifestProcessor(densities,
         tmp.resolve("manifest-filtered/AndroidManifest.xml")).process(manifest);
     assertThat((Object) modified).isNotNull();
-    checkModification(modified, ImmutableList.of("ldpi", "xxhdpi"));
+    checkModification(modified, ImmutableList.<String>of("ldpi", "xxhdpi"));
   }
 
   @Test public void testMalformedManifest() throws Exception {
diff --git a/src/test/java/com/google/devtools/build/android/DensitySpecificResourceFilterTest.java b/src/test/java/com/google/devtools/build/android/DensitySpecificResourceFilterTest.java
index 628dc3b..03f38e9 100644
--- a/src/test/java/com/google/devtools/build/android/DensitySpecificResourceFilterTest.java
+++ b/src/test/java/com/google/devtools/build/android/DensitySpecificResourceFilterTest.java
@@ -132,7 +132,8 @@
   @Test public void testUnknownDensityFails() {
     try {
       checkTransformedResources(
-          ImmutableList.of(), ImmutableList.of(), ImmutableList.of("xxhdpi", "322dpi"));
+          ImmutableList.<String>of(), ImmutableList.<String>of(),
+          ImmutableList.of("xxhdpi", "322dpi"));
       fail("expected MergingException");
     } catch (MergingException expected) {
     }
diff --git a/src/test/java/com/google/devtools/build/android/DependencyAndroidDataTest.java b/src/test/java/com/google/devtools/build/android/DependencyAndroidDataTest.java
index 769b468..5aef80c 100644
--- a/src/test/java/com/google/devtools/build/android/DependencyAndroidDataTest.java
+++ b/src/test/java/com/google/devtools/build/android/DependencyAndroidDataTest.java
@@ -105,7 +105,7 @@
                 ":assets:AndroidManifest.xml:r.txt:symbols.bin", fileSystem))
         .isEqualTo(
             new DependencyAndroidData(
-                ImmutableList.of(), ImmutableList.of(assets), manifest, rTxt, symbols, null));
+                ImmutableList.<Path>of(), ImmutableList.of(assets), manifest, rTxt, symbols, null));
   }
 
   @Test public void flagParseWithEmptyAssets() throws Exception{
@@ -113,7 +113,7 @@
             DependencyAndroidData.valueOf("res::AndroidManifest.xml:r.txt:symbols.bin", fileSystem))
         .isEqualTo(
             new DependencyAndroidData(
-                ImmutableList.of(res), ImmutableList.of(), manifest, rTxt, symbols, null));
+                ImmutableList.of(res), ImmutableList.<Path>of(), manifest, rTxt, symbols, null));
   }
 
   @Test public void flagParseWithEmptyResourcesAndAssets() throws Exception{
@@ -121,7 +121,7 @@
             DependencyAndroidData.valueOf("::AndroidManifest.xml:r.txt:symbols.bin", fileSystem))
         .isEqualTo(
             new DependencyAndroidData(
-                ImmutableList.of(), ImmutableList.of(), manifest, rTxt, symbols, null));
+                ImmutableList.<Path>of(), ImmutableList.<Path>of(), manifest, rTxt, symbols, null));
   }
 
   @Test public void flagNoManifestFails() {
diff --git a/src/test/java/com/google/devtools/build/android/ManifestMergerActionTest.java b/src/test/java/com/google/devtools/build/android/ManifestMergerActionTest.java
index 5e3cf8e..9b989ad 100644
--- a/src/test/java/com/google/devtools/build/android/ManifestMergerActionTest.java
+++ b/src/test/java/com/google/devtools/build/android/ManifestMergerActionTest.java
@@ -173,8 +173,8 @@
         .getManifest();
 
     // libFoo manifest merging
-    List<String> args =
-        generateArgs(libFooManifest, ImmutableMap.of(), true, ImmutableMap.of(), "", libFooOutput);
+    List<String> args = generateArgs(libFooManifest, ImmutableMap.<Path, String>of(), true,
+        ImmutableMap.<String, String>of(), "", libFooOutput);
     ManifestMergerAction.main(args.toArray(new String[0]));
     assertThat(Joiner.on(" ")
         .join(Files.readAllLines(libFooOutput, UTF_8))
@@ -186,14 +186,8 @@
             + "</manifest>");
 
     // libBar manifest merging
-    args =
-        generateArgs(
-            libBarManifest,
-            ImmutableMap.of(),
-            true,
-            ImmutableMap.of(),
-            "com.google.libbar",
-            libBarOutput);
+    args = generateArgs(libBarManifest, ImmutableMap.<Path, String>of(), true,
+        ImmutableMap.<String, String>of(), "com.google.libbar", libBarOutput);
     ManifestMergerAction.main(args.toArray(new String[0]));
     assertThat(Joiner.on(" ")
         .join(Files.readAllLines(libBarOutput, UTF_8))
diff --git a/src/test/java/com/google/devtools/build/android/ParsedAndroidDataBuilder.java b/src/test/java/com/google/devtools/build/android/ParsedAndroidDataBuilder.java
index 59cae58..21e79da 100644
--- a/src/test/java/com/google/devtools/build/android/ParsedAndroidDataBuilder.java
+++ b/src/test/java/com/google/devtools/build/android/ParsedAndroidDataBuilder.java
@@ -48,7 +48,10 @@
 
   public static ParsedAndroidData empty() {
     return ParsedAndroidData.of(
-        ImmutableSet.of(), ImmutableMap.of(), ImmutableMap.of(), ImmutableMap.of());
+        ImmutableSet.<MergeConflict>of(),
+        ImmutableMap.<DataKey, DataResource>of(),
+        ImmutableMap.<DataKey, DataResource>of(),
+        ImmutableMap.<DataKey, DataAsset>of());
   }
 
   public static ParsedAndroidDataBuilder buildOn(
diff --git a/src/test/java/com/google/devtools/build/android/ParsedAndroidDataSubject.java b/src/test/java/com/google/devtools/build/android/ParsedAndroidDataSubject.java
index 824a109..07c6fa4 100644
--- a/src/test/java/com/google/devtools/build/android/ParsedAndroidDataSubject.java
+++ b/src/test/java/com/google/devtools/build/android/ParsedAndroidDataSubject.java
@@ -31,14 +31,14 @@
 
   public void isEqualTo(ParsedAndroidData expectation) {
     List<String> errors = new ArrayList<>();
-    this.compareDataValues(
+    this.<DataAsset>compareDataValues(
         actual().iterateAssetEntries(), expectation.iterateAssetEntries(), errors, "assets");
-    this.compareDataValues(
+    this.<DataResource>compareDataValues(
         actual().iterateCombiningEntries(),
         expectation.iterateCombiningEntries(),
         errors,
         "combining");
-    this.compareDataValues(
+    this.<DataResource>compareDataValues(
         actual().iterateOverwritableEntries(),
         expectation.iterateOverwritableEntries(),
         errors,
diff --git a/src/test/java/com/google/devtools/build/android/ParsedAndroidDataTest.java b/src/test/java/com/google/devtools/build/android/ParsedAndroidDataTest.java
index d296252..e7a55bc 100644
--- a/src/test/java/com/google/devtools/build/android/ParsedAndroidDataTest.java
+++ b/src/test/java/com/google/devtools/build/android/ParsedAndroidDataTest.java
@@ -47,7 +47,7 @@
   @Before
   public void createCleanEnvironment() {
     fs = Jimfs.newFileSystem();
-    fqnFactory = FullyQualifiedName.Factory.from(ImmutableList.of());
+    fqnFactory = FullyQualifiedName.Factory.from(ImmutableList.<String>of());
   }
 
   @Test
@@ -98,9 +98,10 @@
                 ImmutableSet.of(
                     MergeConflict.of(
                         key, DataValueFile.of(assetSource), DataValueFile.of(otherAssetSource))),
-                ImmutableMap.of(),
-                ImmutableMap.of(),
-                ImmutableMap.of(key, DataValueFile.of(otherAssetSource.overwrite(assetSource)))));
+                ImmutableMap.<DataKey, DataResource>of(),
+                ImmutableMap.<DataKey, DataResource>of(),
+                ImmutableMap.<DataKey, DataAsset>of(
+                    key, DataValueFile.of(otherAssetSource.overwrite(assetSource)))));
   }
 
   @Test
@@ -141,7 +142,7 @@
                     .buildDependency()));
 
     FullyQualifiedName.Factory fqnFactory =
-        FullyQualifiedName.Factory.from(ImmutableList.of("hdpi", "v4"));
+        FullyQualifiedName.Factory.from(ImmutableList.<String>of("hdpi", "v4"));
     FullyQualifiedName drawable = fqnFactory.parse("drawable/seven_eight");
     assertThat(dataSet.getOverwritingResources())
         .containsExactly(
@@ -182,7 +183,9 @@
     ParsedAndroidData dataSet =
         ParsedAndroidData.from(
             new UnvalidatedAndroidData(
-                ImmutableList.of(root), ImmutableList.of(), root.resolve("AndroidManifest.xml")));
+                ImmutableList.of(root),
+                ImmutableList.<Path>of(),
+                root.resolve("AndroidManifest.xml")));
 
     FullyQualifiedName layoutFoo = fqnFactory.parse("layout/foo");
     FullyQualifiedName drawableMenu = fqnFactory.parse("drawable/menu");
@@ -359,7 +362,7 @@
                         DataResourceXml.createWithNoNamespace(
                             otherRootValuesPath,
                             ResourcesAttribute.of(attributeFoo, "foo", "fooVal")))),
-                ImmutableMap.of(
+                ImmutableMap.<DataKey, DataResource>of(
                     drawableMenu, // key
                     DataValueFile.of(
                         otherRootDrawableMenuPath.overwrite(rootDrawableMenuPath)), // value
@@ -373,12 +376,12 @@
                         SimpleXmlResourceValue.createWithValue(
                             SimpleXmlResourceValue.Type.STRING, "way out")) // value
                     ),
-                ImmutableMap.of(
+                ImmutableMap.<DataKey, DataResource>of(
                     idSomeId, // key
                     DataResourceXml.createWithNoNamespace(
                         rootValuesPath, IdXmlResourceValue.of()) // value
                     ),
-                ImmutableMap.of()));
+                ImmutableMap.<DataKey, DataAsset>of()));
   }
 
   @Test
@@ -544,7 +547,7 @@
             .createManifest("AndroidManifest.xml", "com.carroll.lewis", "")
             .buildParsed();
     FullyQualifiedName.Factory fqnV21Factory =
-        FullyQualifiedName.Factory.from(ImmutableList.of("v21"));
+        FullyQualifiedName.Factory.from(ImmutableList.<String>of("v21"));
     FullyQualifiedName drawableKey = fqnV21Factory.parse("drawable/some_drawable");
     Path drawablePath = root.resolve("res/drawable-v21/some_drawable.xml");
     assertThat(dataSet.getOverwritingResources())
diff --git a/src/test/java/com/google/devtools/build/android/RClassGeneratorActionTest.java b/src/test/java/com/google/devtools/build/android/RClassGeneratorActionTest.java
index 2f3ae78..e03348c 100644
--- a/src/test/java/com/google/devtools/build/android/RClassGeneratorActionTest.java
+++ b/src/test/java/com/google/devtools/build/android/RClassGeneratorActionTest.java
@@ -109,7 +109,7 @@
     Path jarPath = tempDir.resolve("app_resources.jar");
 
     RClassGeneratorAction.main(
-        ImmutableList.of(
+        ImmutableList.<String>of(
                 "--primaryRTxt",
                 binarySymbols.toString(),
                 "--primaryManifest",
@@ -165,7 +165,7 @@
     Path jarPath = tempDir.resolve("app_resources.jar");
 
     RClassGeneratorAction.main(
-        ImmutableList.of(
+        ImmutableList.<String>of(
                 "--library",
                 libFooSymbols + "," + libFooManifest,
                 "--library",
@@ -212,12 +212,11 @@
 
     Path jarPath = tempDir.resolve("app_resources.jar");
 
-    RClassGeneratorAction.main(
-        ImmutableList.of(
-                "--primaryRTxt", binarySymbols.toString(),
-                "--primaryManifest", binaryManifest.toString(),
-                "--classJarOutput", jarPath.toString())
-            .toArray(new String[0]));
+    RClassGeneratorAction.main(ImmutableList.<String>of(
+        "--primaryRTxt", binarySymbols.toString(),
+        "--primaryManifest", binaryManifest.toString(),
+        "--classJarOutput", jarPath.toString()
+    ).toArray(new String[0]));
 
     assertThat(Files.exists(jarPath)).isTrue();
     assertThat(Files.getLastModifiedTime(jarPath)).isEqualTo(FileTime.fromMillis(0));
@@ -240,8 +239,9 @@
   @Test
   public void noBinary() throws Exception {
     Path jarPath = tempDir.resolve("app_resources.jar");
-    RClassGeneratorAction.main(
-        ImmutableList.of("--classJarOutput", jarPath.toString()).toArray(new String[0]));
+    RClassGeneratorAction.main(ImmutableList.<String>of(
+        "--classJarOutput", jarPath.toString()
+    ).toArray(new String[0]));
 
     assertThat(Files.exists(jarPath)).isTrue();
     assertThat(Files.getLastModifiedTime(jarPath)).isEqualTo(FileTime.fromMillis(0));
@@ -271,7 +271,7 @@
         "int string ok 0x1");
     Path jarPath = tempDir.resolve("app_resources.jar");
     RClassGeneratorAction.main(
-        ImmutableList.of(
+        ImmutableList.<String>of(
                 "--primaryRTxt",
                 binarySymbols.toString(),
                 "--primaryManifest",
@@ -313,13 +313,13 @@
     Path binarySymbols = createFile("R.txt", "");
     Path jarPath = tempDir.resolve("app_resources.jar");
     RClassGeneratorAction.main(
-        ImmutableList.of(
-                "--primaryRTxt",
-                binarySymbols.toString(),
-                "--primaryManifest",
-                binaryManifest.toString(),
-                "--classJarOutput",
-                jarPath.toString())
+        ImmutableList.<String>of(
+            "--primaryRTxt",
+            binarySymbols.toString(),
+            "--primaryManifest",
+            binaryManifest.toString(),
+            "--classJarOutput",
+            jarPath.toString())
             .toArray(new String[0]));
 
     assertThat(Files.exists(jarPath)).isTrue();
diff --git a/src/test/java/com/google/devtools/build/android/SerializedAndroidDataTest.java b/src/test/java/com/google/devtools/build/android/SerializedAndroidDataTest.java
index cc3cba7..eb9837f 100644
--- a/src/test/java/com/google/devtools/build/android/SerializedAndroidDataTest.java
+++ b/src/test/java/com/google/devtools/build/android/SerializedAndroidDataTest.java
@@ -78,10 +78,11 @@
   @Test
   public void flagParseWithEmptyResources() throws Exception {
     Truth.assertThat(
-            SerializedAndroidData.valueOf(";assets;//some_target/foo:foo;symbols.bin", fileSystem))
+            SerializedAndroidData.valueOf(
+                ";assets;//some_target/foo:foo;symbols.bin", fileSystem))
         .isEqualTo(
             new SerializedAndroidData(
-                ImmutableList.of(), ImmutableList.of(assets), label, symbols));
+                ImmutableList.<Path>of(), ImmutableList.of(assets), label, symbols));
   }
 
   @Test
@@ -89,7 +90,8 @@
     Truth.assertThat(
             SerializedAndroidData.valueOf("res;;//some_target/foo:foo;symbols.bin", fileSystem))
         .isEqualTo(
-            new SerializedAndroidData(ImmutableList.of(res), ImmutableList.of(), label, symbols));
+            new SerializedAndroidData(
+                ImmutableList.of(res), ImmutableList.<Path>of(), label, symbols));
   }
 
   @Test
@@ -97,7 +99,8 @@
     Truth.assertThat(
             SerializedAndroidData.valueOf(";;//some_target/foo:foo;symbols.bin", fileSystem))
         .isEqualTo(
-            new SerializedAndroidData(ImmutableList.of(), ImmutableList.of(), label, symbols));
+            new SerializedAndroidData(
+                ImmutableList.<Path>of(), ImmutableList.<Path>of(), label, symbols));
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/android/SplitConfigurationFilterTest.java b/src/test/java/com/google/devtools/build/android/SplitConfigurationFilterTest.java
index e3c1195..db55ac1 100644
--- a/src/test/java/com/google/devtools/build/android/SplitConfigurationFilterTest.java
+++ b/src/test/java/com/google/devtools/build/android/SplitConfigurationFilterTest.java
@@ -34,7 +34,8 @@
   @Test
   public void mapFilenamesToSplitFlagsShouldReturnEmptyMapForEmptyInput()
       throws UnrecognizedSplitsException {
-    assertThat(mapFilenamesToSplitFlags(ImmutableList.of(), ImmutableList.of())).isEmpty();
+    assertThat(mapFilenamesToSplitFlags(ImmutableList.<String>of(), ImmutableList.<String>of()))
+        .isEmpty();
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/android/UnvalidatedAndroidDataTest.java b/src/test/java/com/google/devtools/build/android/UnvalidatedAndroidDataTest.java
index ee97a77..2a662f7 100644
--- a/src/test/java/com/google/devtools/build/android/UnvalidatedAndroidDataTest.java
+++ b/src/test/java/com/google/devtools/build/android/UnvalidatedAndroidDataTest.java
@@ -58,19 +58,33 @@
   }
 
   @Test public void flagParseWithEmptyResources() throws Exception {
-    Truth.assertThat(UnvalidatedAndroidData.valueOf(":assets:AndroidManifest.xml", fileSystem))
-        .isEqualTo(
-            new UnvalidatedAndroidData(ImmutableList.of(), ImmutableList.of(assets), manifest));
+    Truth.assertThat(
+        UnvalidatedAndroidData.valueOf(
+            ":assets:AndroidManifest.xml", fileSystem)
+        ).isEqualTo(
+            new UnvalidatedAndroidData(ImmutableList.<Path>of(),
+                ImmutableList.of(assets),
+                manifest));
   }
 
   @Test public void flagParseWithEmptyAssets() throws Exception {
-    Truth.assertThat(UnvalidatedAndroidData.valueOf("res::AndroidManifest.xml", fileSystem))
-        .isEqualTo(new UnvalidatedAndroidData(ImmutableList.of(res), ImmutableList.of(), manifest));
+    Truth.assertThat(
+        UnvalidatedAndroidData.valueOf(
+            "res::AndroidManifest.xml", fileSystem)
+        ).isEqualTo(
+            new UnvalidatedAndroidData(ImmutableList.of(res),
+                ImmutableList.<Path>of(),
+                manifest));
   }
 
   @Test public void flagParseWithEmptyResourcesAndAssets() throws Exception {
-    Truth.assertThat(UnvalidatedAndroidData.valueOf("::AndroidManifest.xml", fileSystem))
-        .isEqualTo(new UnvalidatedAndroidData(ImmutableList.of(), ImmutableList.of(), manifest));
+    Truth.assertThat(
+        UnvalidatedAndroidData.valueOf(
+            "::AndroidManifest.xml", fileSystem)
+        ).isEqualTo(
+            new UnvalidatedAndroidData(ImmutableList.<Path>of(),
+                ImmutableList.<Path>of(),
+                manifest));
   }
 
   @Test public void flagNoManifestFails() {
diff --git a/src/test/java/com/google/devtools/build/android/UnvalidatedAndroidDirectoriesTest.java b/src/test/java/com/google/devtools/build/android/UnvalidatedAndroidDirectoriesTest.java
index a0b1129..1d70d81 100644
--- a/src/test/java/com/google/devtools/build/android/UnvalidatedAndroidDirectoriesTest.java
+++ b/src/test/java/com/google/devtools/build/android/UnvalidatedAndroidDirectoriesTest.java
@@ -52,18 +52,30 @@
   }
 
   @Test public void flagParseWithEmptyAssets() throws Exception {
-    Truth.assertThat(UnvalidatedAndroidDirectories.valueOf("res:", fileSystem))
-        .isEqualTo(new UnvalidatedAndroidDirectories(ImmutableList.of(res), ImmutableList.of()));
+    Truth.assertThat(
+        UnvalidatedAndroidDirectories.valueOf(
+            "res:", fileSystem)
+    ).isEqualTo(
+        new UnvalidatedAndroidDirectories(ImmutableList.of(res),
+            ImmutableList.<Path>of()));
   }
 
   @Test public void flagParseWithEmptyResources() throws Exception {
-    Truth.assertThat(UnvalidatedAndroidDirectories.valueOf(":assets", fileSystem))
-        .isEqualTo(new UnvalidatedAndroidDirectories(ImmutableList.of(), ImmutableList.of(assets)));
+    Truth.assertThat(
+        UnvalidatedAndroidDirectories.valueOf(
+            ":assets", fileSystem)
+    ).isEqualTo(
+        new UnvalidatedAndroidDirectories(ImmutableList.<Path>of(),
+            ImmutableList.of(assets)));
   }
 
   @Test public void flagParseWithEmptyResourcesAndAssets() throws Exception {
-    Truth.assertThat(UnvalidatedAndroidDirectories.valueOf(":", fileSystem))
-        .isEqualTo(new UnvalidatedAndroidDirectories(ImmutableList.of(), ImmutableList.of()));
+    Truth.assertThat(
+        UnvalidatedAndroidDirectories.valueOf(
+            ":", fileSystem)
+    ).isEqualTo(
+        new UnvalidatedAndroidDirectories(ImmutableList.<Path>of(),
+            ImmutableList.<Path>of()));
   }
 
 }
diff --git a/src/tools/android/java/com/google/devtools/build/android/Aapt2ResourcePackagingAction.java b/src/tools/android/java/com/google/devtools/build/android/Aapt2ResourcePackagingAction.java
index 4ef23e7..83b628c 100644
--- a/src/tools/android/java/com/google/devtools/build/android/Aapt2ResourcePackagingAction.java
+++ b/src/tools/android/java/com/google/devtools/build/android/Aapt2ResourcePackagingAction.java
@@ -125,82 +125,83 @@
 
       profiler.recordEndOf("merging");
 
-      profiler.startTask("compile");
-      final ResourceCompiler compiler =
-          ResourceCompiler.create(
-              executorService,
-              compiledResources,
-              aaptConfigOptions.aapt2,
-              aaptConfigOptions.buildToolsVersion);
+     
+        profiler.startTask("compile");
+        final ResourceCompiler compiler =
+            ResourceCompiler.create(
+                executorService,
+                compiledResources,
+                aaptConfigOptions.aapt2,
+                aaptConfigOptions.buildToolsVersion);
 
-      CompiledResources compiled =
-          options
-              .primaryData
-              .processDataBindings(
-                  options.dataBindingInfoOut, options.packageForR, databindingResourcesRoot)
-              .compile(compiler, compiledResources)
-              .processManifest(
-                  manifest ->
-                      AndroidManifestProcessor.with(STD_LOGGER)
-                          .processManifest(
-                              options.applicationId,
-                              options.versionCode,
-                              options.versionName,
-                              manifest,
-                              processedManifest))
-              .processManifest(
-                  manifest ->
-                      new DensitySpecificManifestProcessor(densities, densityManifest)
-                          .process(manifest));
-      profiler.recordEndOf("compile").startTask("link");
-      // Write manifestOutput now before the dummy manifest is created.
-      if (options.manifestOutput != null) {
-        AndroidResourceOutputs.copyManifestToOutput(compiled, options.manifestOutput);
-      }
+        CompiledResources compiled =
+            options
+                .primaryData
+                .processDataBindings(
+                    options.dataBindingInfoOut, options.packageForR, databindingResourcesRoot)
+                .compile(compiler, compiledResources)
+                .processManifest(
+                    manifest ->
+                        AndroidManifestProcessor.with(STD_LOGGER)
+                            .processManifest(
+                                options.applicationId,
+                                options.versionCode,
+                                options.versionName,
+                                manifest,
+                                processedManifest))
+                .processManifest(
+                    manifest ->
+                        new DensitySpecificManifestProcessor(densities, densityManifest)
+                            .process(manifest));
+        profiler.recordEndOf("compile").startTask("link");
+        // Write manifestOutput now before the dummy manifest is created.
+        if (options.manifestOutput != null) {
+          AndroidResourceOutputs.copyManifestToOutput(compiled, options.manifestOutput);
+        }
 
-      List<CompiledResources> compiledResourceDeps =
-          // Last defined dependencies will overwrite previous one, so always place direct
-          // after transitive.
-          concat(options.transitiveData.stream(), options.directData.stream())
-              .map(DependencyAndroidData::getCompiledSymbols)
-              .collect(toList());
+        List<CompiledResources> compiledResourceDeps =
+            // Last defined dependencies will overwrite previous one, so always place direct
+            // after transitive.
+            concat(options.transitiveData.stream(), options.directData.stream())
+                .map(DependencyAndroidData::getCompiledSymbols)
+                .collect(toList());
 
-      List<Path> assetDirs =
-          concat(options.transitiveData.stream(), options.directData.stream())
-              .flatMap(dep -> dep.assetDirs.stream())
-              .collect(toList());
-      assetDirs.addAll(options.primaryData.assetDirs);
+        List<Path> assetDirs =
+            concat(options.transitiveData.stream(), options.directData.stream())
+                .flatMap(dep -> dep.assetDirs.stream())
+                .collect(toList());
+        assetDirs.addAll(options.primaryData.assetDirs);
 
-      final PackagedResources packagedResources =
-          ResourceLinker.create(aaptConfigOptions.aapt2, linkedOut)
-              .profileUsing(profiler)
-              .customPackage(options.packageForR)
-              .outputAsProto(aaptConfigOptions.resourceTableAsProto)
-              .dependencies(ImmutableList.of(StaticLibrary.from(aaptConfigOptions.androidJar)))
-              .include(compiledResourceDeps)
-              .withAssets(assetDirs)
-              .buildVersion(aaptConfigOptions.buildToolsVersion)
-              .conditionalKeepRules(aaptConfigOptions.conditionalKeepRules == TriState.YES)
-              .filterToDensity(densities)
-              .includeOnlyConfigs(aaptConfigOptions.resourceConfigs)
-              .link(compiled)
-              .copyPackageTo(options.packagePath)
-              .copyProguardTo(options.proguardOutput)
-              .copyMainDexProguardTo(options.mainDexProguardOutput)
-              .createSourceJar(options.srcJarOutput)
-              .copyRTxtTo(options.rOutput);
-      profiler.recordEndOf("link");
-      if (options.resourcesOutput != null) {
-        profiler.startTask("package");
-        // The compiled resources and the merged resources should be the same.
-        // TODO(corysmith): Decompile or otherwise provide the exact resources in the apk.
-        ResourcesZip.fromApk(
-                mergedAndroidData.getResourceDir(),
-                packagedResources.getApk(),
-                packagedResources.getResourceIds())
-            .writeTo(options.resourcesOutput, false /* compress */);
-        profiler.recordEndOf("package");
+        final PackagedResources packagedResources =
+            ResourceLinker.create(aaptConfigOptions.aapt2, linkedOut)
+                .profileUsing(profiler)
+                .customPackage(options.packageForR)
+                .outputAsProto(aaptConfigOptions.resourceTableAsProto)
+                .dependencies(ImmutableList.of(StaticLibrary.from(aaptConfigOptions.androidJar)))
+                .include(compiledResourceDeps)
+                .withAssets(assetDirs)
+                .buildVersion(aaptConfigOptions.buildToolsVersion)
+                .conditionalKeepRules(aaptConfigOptions.conditionalKeepRules == TriState.YES)
+                .filterToDensity(densities)
+                .includeOnlyConfigs(aaptConfigOptions.resourceConfigs)
+                .link(compiled)
+                .copyPackageTo(options.packagePath)
+                .copyProguardTo(options.proguardOutput)
+                .copyMainDexProguardTo(options.mainDexProguardOutput)
+                .createSourceJar(options.srcJarOutput)
+                .copyRTxtTo(options.rOutput);
+        profiler.recordEndOf("link");
+        if (options.resourcesOutput != null) {
+          profiler.startTask("package");
+          // The compiled resources and the merged resources should be the same.
+          // TODO(corysmith): Decompile or otherwise provide the exact resources in the apk.
+          ResourcesZip.fromApk(
+                  mergedAndroidData.getResourceDir(),
+                  packagedResources.getApk(),
+                  packagedResources.getResourceIds())
+              .writeTo(options.resourcesOutput, false /* compress */);
+          profiler.recordEndOf("package");
+        }
       }
     }
   }
-}
diff --git a/src/tools/android/java/com/google/devtools/build/android/AarGeneratorAction.java b/src/tools/android/java/com/google/devtools/build/android/AarGeneratorAction.java
index 3f3c35c..20e9e6c 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AarGeneratorAction.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AarGeneratorAction.java
@@ -169,7 +169,7 @@
               null,
               VariantType.LIBRARY,
               null,
-              /* filteredResources= */ ImmutableList.of(),
+              /* filteredResources= */ ImmutableList.<String>of(),
               options.throwOnResourceConflict);
       logger.fine(String.format("Merging finished at %dms", timer.elapsed(TimeUnit.MILLISECONDS)));
 
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidCompiledDataDeserializer.java b/src/tools/android/java/com/google/devtools/build/android/AndroidCompiledDataDeserializer.java
index 0e6209b..fb4d93d 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AndroidCompiledDataDeserializer.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AndroidCompiledDataDeserializer.java
@@ -28,6 +28,9 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.io.LittleEndianDataInputStream;
 import com.google.devtools.build.android.FullyQualifiedName.Factory;
+import com.google.devtools.build.android.proto.SerializeFormat;
+import com.google.devtools.build.android.proto.SerializeFormat.Header;
+import com.google.devtools.build.android.xml.ResourcesAttribute.AttributeType;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
@@ -77,8 +80,7 @@
   private void readResourceTable(
       LittleEndianDataInputStream resourceTableStream,
       KeyValueConsumers consumers,
-      Factory fqnFactory)
-      throws IOException {
+      Factory fqnFactory) throws IOException {
     long alignedSize = resourceTableStream.readLong();
     Preconditions.checkArgument(alignedSize <= Integer.MAX_VALUE);
 
@@ -111,27 +113,34 @@
               new SimpleEntry<FullyQualifiedName, Boolean>(fqn, packageName.isEmpty()));
 
           List<ConfigValue> configValues = resource.getConfigValueList();
-          if (configValues.isEmpty() && resource.getVisibility().getLevel() == Level.PUBLIC) {
+          if (configValues.isEmpty()
+              && resource.getVisibility().getLevel() == Level.PUBLIC) {
             int sourceIndex = resource.getVisibility().getSource().getPathIdx();
 
             String source = sourcePool.get(sourceIndex);
             DataSource dataSource = DataSource.of(Paths.get(source));
 
-            DataResourceXml dataResourceXml =
-                DataResourceXml.fromPublic(dataSource, resourceType, resource.getEntryId().getId());
+            DataResourceXml dataResourceXml = DataResourceXml
+                .fromPublic(dataSource, resourceType, resource.getEntryId().getId());
             consumers.combiningConsumer.accept(fqn, dataResourceXml);
-          } else if (packageName.isEmpty()) { // This means this resource is not in the android sdk
+          } else if (packageName.isEmpty()) {// This means this resource is not in the android sdk
             Preconditions.checkArgument(configValues.size() == 1);
-            int sourceIndex = configValues.get(0).getValue().getSource().getPathIdx();
+            int sourceIndex =
+                configValues.get(0)
+                    .getValue()
+                    .getSource()
+                    .getPathIdx();
 
             String source = sourcePool.get(sourceIndex);
             DataSource dataSource = DataSource.of(Paths.get(source));
 
             Value resourceValue = resource.getConfigValue(0).getValue();
             DataResourceXml dataResourceXml =
-                DataResourceXml.from(resourceValue, dataSource, resourceType, fullyQualifiedNames);
+                DataResourceXml
+                    .from(resourceValue, dataSource, resourceType, fullyQualifiedNames);
 
-            if (resourceType == ResourceType.ID || resourceType == ResourceType.STYLEABLE) {
+            if (resourceType == ResourceType.ID
+                || resourceType == ResourceType.STYLEABLE) {
               consumers.combiningConsumer.accept(fqn, dataResourceXml);
             } else {
               consumers.overwritingConsumer.accept(fqn, dataResourceXml);
@@ -156,14 +165,13 @@
   private void readCompiledFile(
       LittleEndianDataInputStream compiledFileStream,
       KeyValueConsumers consumers,
-      Factory fqnFactory)
-      throws IOException {
-    // Skip aligned size. We don't need it here.
+      Factory fqnFactory) throws IOException {
+    //Skip aligned size. We don't need it here.
     Preconditions.checkArgument(compiledFileStream.skipBytes(8) == 8);
 
     int resFileHeaderSize = compiledFileStream.readInt();
 
-    // Skip data payload size. We don't need it here.
+    //Skip data payload size. We don't need it here.
     Preconditions.checkArgument(compiledFileStream.skipBytes(8) == 8);
 
     byte[] file = new byte[resFileHeaderSize];
@@ -193,10 +201,35 @@
   }
 
   private void readAttributesFile(
-      InputStream resourceFileStream, FileSystem fileSystem, KeyValueConsumers consumers)
-      throws IOException {
-    AndroidParsedDataDeserializer.deserializeEntries(
-        consumers, resourceFileStream, fileSystem, ImmutableSet.of());
+      InputStream resourceFileStream,
+      FileSystem fileSystem,
+      KeyValueConsumers consumers) throws IOException {
+
+    Header header = Header.parseDelimitedFrom(resourceFileStream);
+    List<DataKey> fullyQualifiedNames = new ArrayList<>();
+    for (int i = 0; i < header.getEntryCount(); i++) {
+      SerializeFormat.DataKey protoKey =
+          SerializeFormat.DataKey.parseDelimitedFrom(resourceFileStream);
+      fullyQualifiedNames.add(FullyQualifiedName.fromProto(protoKey));
+    }
+
+    DataSourceTable sourceTable = DataSourceTable.read(resourceFileStream, fileSystem, header);
+
+    for (DataKey fullyQualifiedName : fullyQualifiedNames) {
+      SerializeFormat.DataValue protoValue =
+          SerializeFormat.DataValue.parseDelimitedFrom(resourceFileStream);
+      DataSource source = sourceTable.sourceFromId(protoValue.getSourceId());
+      DataResourceXml dataResourceXml =
+          (DataResourceXml) DataResourceXml.from(protoValue, source);
+      AttributeType attributeType =
+          AttributeType.valueOf(protoValue.getXmlValue().getValueType());
+
+      if (attributeType.isCombining()) {
+        consumers.combiningConsumer.accept(fullyQualifiedName, dataResourceXml);
+      } else {
+        consumers.overwritingConsumer.accept(fullyQualifiedName, dataResourceXml);
+      }
+    }
   }
 
   @Override
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidDataSerializer.java b/src/tools/android/java/com/google/devtools/build/android/AndroidDataSerializer.java
index 9a1c3a0..2304f3c 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AndroidDataSerializer.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AndroidDataSerializer.java
@@ -13,23 +13,17 @@
 // limitations under the License.
 package com.google.devtools.build.android;
 
-import com.google.common.base.MoreObjects;
-import com.google.common.base.Preconditions;
 import com.google.common.base.Stopwatch;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
 import com.google.devtools.build.android.proto.SerializeFormat;
-import com.google.devtools.build.android.proto.SerializeFormat.DataValue.Builder;
 import com.google.devtools.build.android.proto.SerializeFormat.Header;
-import com.google.devtools.build.android.xml.Namespaces;
 import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Map;
 import java.util.Map.Entry;
 import java.util.NavigableMap;
 import java.util.Set;
@@ -39,128 +33,6 @@
 
 /** Serializes {@link DataKey},{@link DataValue} entries to a binary file. */
 public class AndroidDataSerializer {
-
-  /** A visitor to accumulate the necessary state to write a resource entry. */
-  public interface SerializeEntryVisitor extends Writeable {
-    SerializeEntryVisitor setSource(DataSource dataSource);
-
-    SerializeEntryVisitor setKey(DataKey key);
-
-    SerializeEntryVisitor overwrite(Set<DataSource> dataSource);
-
-    SerializeEntryVisitor setXml(XmlResourceValue value);
-
-    SerializeEntryVisitor setNamespaces(Namespaces namespaces);
-  }
-
-  private static class DataValueBuilder implements SerializeEntryVisitor {
-
-    private final Builder builder;
-    private final WritablePool<DataKey> keys;
-    private final WritablePool<DataSource> sources;
-    private final WritablePool<XmlResourceValue> xml;
-    private final WritablePool<Namespaces> namespaces;
-
-    public DataValueBuilder(
-        Builder builder,
-        WritablePool<DataKey> keys,
-        WritablePool<DataSource> sources,
-        WritablePool<XmlResourceValue> xml,
-        WritablePool<Namespaces> namespaces) {
-      this.builder = Preconditions.checkNotNull(builder);
-      this.keys = Preconditions.checkNotNull(keys);
-      this.sources = sources;
-      this.xml = xml;
-      this.namespaces = namespaces;
-    }
-
-    static DataValueBuilder create(
-        WritablePool<DataKey> keys,
-        WritablePool<DataSource> sources,
-        WritablePool<XmlResourceValue> xml,
-        WritablePool<Namespaces> namespaces) {
-      return new DataValueBuilder(
-          SerializeFormat.DataValue.newBuilder(), keys, sources, xml, namespaces);
-    }
-
-    @Override
-    public SerializeEntryVisitor setSource(DataSource dataSource) {
-      builder.setSourceId(sources.queue(dataSource));
-      overwrite(dataSource.overrides());
-      return this;
-    }
-
-    @Override
-    public SerializeEntryVisitor setKey(DataKey key) {
-      builder.setKeyId(keys.queue(key));
-      return this;
-    }
-
-    @Override
-    public SerializeEntryVisitor overwrite(Set<DataSource> dataSource) {
-      for (DataSource source : dataSource) {
-        builder.addOverwrittenSourceId(sources.queue(source));
-      }
-      return this;
-    }
-
-    @Override
-    public SerializeEntryVisitor setXml(XmlResourceValue value) {
-      builder.setXmlId(xml.queue(value));
-      return this;
-    }
-
-    @Override
-    public SerializeEntryVisitor setNamespaces(Namespaces namespaces) {
-      builder.setNamespaceId(this.namespaces.queue(namespaces));
-      return this;
-    }
-
-    @Override
-    public void writeTo(OutputStream out) throws IOException {
-      builder.build().writeDelimitedTo(out);
-    }
-
-    @Override
-    public String toString() {
-      return MoreObjects.toStringHelper(this)
-          .add("builder", builder.build())
-          .add("keys", keys)
-          .add("sources", sources)
-          .add("xml", xml)
-          .add("namespaces", namespaces)
-          .toString();
-    }
-  }
-
-  private static class WritablePool<T extends Writeable> implements Writeable {
-    BiMap<T, Integer> lookup = HashBiMap.create();
-    Integer lastIndex = 0;
-
-    Integer queue(T value) {
-      if (!lookup.containsKey(value)) {
-        lookup.put(value, lastIndex++);
-      }
-      return lookup.get(value);
-    }
-
-    @Override
-    public void writeTo(OutputStream out) throws IOException {
-      final BiMap<Integer, T> indexed = lookup.inverse();
-      for (int idx = 0; idx < lastIndex; idx++) {
-        indexed.get(idx).writeTo(out);
-      }
-    }
-
-    public int size() {
-      return lookup.size();
-    }
-
-    public static <T extends Writeable> WritablePool<T> create() {
-      return new WritablePool<>();
-    }
-  }
-
   private static final Logger logger = Logger.getLogger(AndroidDataSerializer.class.getName());
 
   private final NavigableMap<DataKey, DataValue> entries = new TreeMap<>();
@@ -191,61 +63,54 @@
     if (out.getParent() != null) {
       Files.createDirectories(out.getParent());
     }
-    WritablePool<DataKey> keys = WritablePool.create();
-    WritablePool<DataSource> sources = WritablePool.create();
-    WritablePool<XmlResourceValue> xml = WritablePool.create();
-    WritablePool<Namespaces> namespaces = WritablePool.create();
-
     try (OutputStream outStream =
         new BufferedOutputStream(
             Files.newOutputStream(out, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE))) {
 
       // Set the header for the deserialization process.
+      SerializeFormat.Header.Builder headerBuilder =
+          Header.newBuilder().setEntryCount(entries.size());
 
-      List<SerializeEntryVisitor> values = new ArrayList<>(entries.size());
-      for (Entry<DataKey, DataValue> entry : entries.entrySet()) {
-        values.add(
-            entry
-                .getValue()
-                .serializeTo(
-                    DataValueBuilder.create(keys, sources, xml, namespaces)
-                        .setKey(entry.getKey())));
-      }
+      // Create table of source paths to allow references in the serialization format via an index.
+      ByteArrayOutputStream sourceTableOutputStream = new ByteArrayOutputStream(2048);
+      DataSourceTable sourceTable =
+          DataSourceTable.createAndWrite(entries, sourceTableOutputStream, headerBuilder);
 
-      Header.newBuilder()
-          .setKeyCount(keys.size())
-          .setSourceCount(sources.size())
-          .setValueCount(values.size())
-          .setXmlCount(xml.size())
-          .setNamespacesCount(namespaces.size())
-          .build()
-          .writeDelimitedTo(outStream);
+      headerBuilder.build().writeDelimitedTo(outStream);
 
-      /*
-      Serialization order:
-        keys
-        sources
-        values
-        xml
-        namespaces
-
-      This allows deserializing keys for R generation, as well as sources and entries for
-      lightweight merging.
-      */
-
-      keys.writeTo(outStream);
-      sources.writeTo(outStream);
-      for (SerializeEntryVisitor value : values) {
-        value.writeTo(outStream);
-      }
-      xml.writeTo(outStream);
-      namespaces.writeTo(outStream);
-
-      outStream.flush();
+      writeKeyValuesTo(entries, outStream, sourceTable, sourceTableOutputStream.toByteArray());
     }
     logger.fine(String.format("Serialized merged in %sms", timer.elapsed(TimeUnit.MILLISECONDS)));
   }
 
+  private void writeKeyValuesTo(
+      NavigableMap<DataKey, DataValue> map,
+      OutputStream outStream,
+      DataSourceTable sourceTable,
+      byte[] sourceTableBytes)
+      throws IOException {
+    Set<Entry<DataKey, DataValue>> entries = map.entrySet();
+    int[] orderedValueSizes = new int[entries.size()];
+    int valueSizeIndex = 0;
+    // Serialize all the values in sorted order to a intermediate buffer, so that the keys
+    // can be associated with a value size.
+    // TODO(corysmith): Tune the size of the byte array.
+    ByteArrayOutputStream valuesOutputStream = new ByteArrayOutputStream(2048);
+    for (Map.Entry<DataKey, DataValue> entry : entries) {
+      orderedValueSizes[valueSizeIndex++] =
+          entry.getValue().serializeTo(sourceTable, valuesOutputStream);
+    }
+    // Serialize all the keys in sorted order
+    valueSizeIndex = 0;
+    for (Map.Entry<DataKey, DataValue> entry : entries) {
+      entry.getKey().serializeTo(outStream, orderedValueSizes[valueSizeIndex++]);
+    }
+    // write the source table
+    outStream.write(sourceTableBytes);
+    // write the values to the output stream.
+    outStream.write(valuesOutputStream.toByteArray());
+  }
+
   /** Queues the key and value for serialization as a entries entry. */
   public void queueForSerialization(DataKey key, DataValue value) {
     entries.put(key, value);
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidDataWriter.java b/src/tools/android/java/com/google/devtools/build/android/AndroidDataWriter.java
index a9770f7..38d38f3 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AndroidDataWriter.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AndroidDataWriter.java
@@ -654,7 +654,7 @@
   }
 
   /** Base interface for writing information to a {@link Writer}. */
-  private interface Segment {
+  private static interface Segment {
     /**
      * Writes the segment contents to a Writer
      *
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidParsedDataDeserializer.java b/src/tools/android/java/com/google/devtools/build/android/AndroidParsedDataDeserializer.java
index 3ded0da..e704c06 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AndroidParsedDataDeserializer.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AndroidParsedDataDeserializer.java
@@ -15,6 +15,7 @@
 
 import com.google.common.base.Stopwatch;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
@@ -23,9 +24,6 @@
 import com.google.devtools.build.android.ParsedAndroidData.KeyValueConsumer;
 import com.google.devtools.build.android.proto.SerializeFormat;
 import com.google.devtools.build.android.proto.SerializeFormat.Header;
-import com.google.devtools.build.android.proto.SerializeFormat.ProtoSource;
-import com.google.devtools.build.android.proto.SerializeFormat.XmlNamespaces;
-import com.google.devtools.build.android.xml.Namespaces;
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
@@ -36,11 +34,12 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 import java.util.logging.Logger;
-import java.util.stream.Collectors;
 
 /** Deserializes {@link DataKey}, {@link DataValue} entries from a binary file. */
 public class AndroidParsedDataDeserializer implements AndroidDataDeserializer {
@@ -88,7 +87,7 @@
   }
 
   public static AndroidParsedDataDeserializer create() {
-    return new AndroidParsedDataDeserializer(ImmutableSet.of());
+    return new AndroidParsedDataDeserializer(ImmutableSet.<String>of());
   }
 
   private AndroidParsedDataDeserializer(ImmutableSet<String> filteredResources) {
@@ -109,8 +108,12 @@
     Stopwatch timer = Stopwatch.createStarted();
     try (InputStream in = Files.newInputStream(inPath, StandardOpenOption.READ)) {
       FileSystem currentFileSystem = inPath.getFileSystem();
-      deserializeEntries(consumers, in, currentFileSystem, filteredResources);
-    } catch (Throwable e) {
+      Header header = Header.parseDelimitedFrom(in);
+      if (header == null) {
+        throw new DeserializationException("No Header found in " + inPath);
+      }
+      readEntriesSegment(consumers, in, currentFileSystem, header);
+    } catch (IOException e) {
       throw new DeserializationException("Error deserializing " + inPath, e);
     } finally {
       logger.fine(
@@ -118,103 +121,59 @@
     }
   }
 
-  public static void deserializeEntries(
-      KeyValueConsumers consumers,
-      InputStream in,
-      FileSystem currentFileSystem,
-      ImmutableSet<String> filteredResources)
+  private void readEntriesSegment(
+      KeyValueConsumers consumers, InputStream in, FileSystem currentFileSystem, Header header)
       throws IOException {
-
-    /*
-      Serialization order:
-         header
-         keys
-         sources
-         values
-         xml
-         namespaces
-    */
-
-    Header header = Header.parseDelimitedFrom(in);
-    if (header == null) {
-      throw new DeserializationException("Invalid Format: no header");
+    int numberOfEntries = header.getEntryCount();
+    Map<DataKey, KeyValueConsumer<DataKey, ? extends DataValue>> keys =
+        Maps.newLinkedHashMapWithExpectedSize(numberOfEntries);
+    for (int i = 0; i < numberOfEntries; i++) {
+      SerializeFormat.DataKey protoKey = SerializeFormat.DataKey.parseDelimitedFrom(in);
+      if (protoKey.hasResourceType()) {
+        FullyQualifiedName resourceName = FullyQualifiedName.fromProto(protoKey);
+        keys.put(
+            resourceName,
+            resourceName.isOverwritable()
+                ? consumers.overwritingConsumer
+                : consumers.combiningConsumer);
+      } else {
+        keys.put(RelativeAssetPath.fromProto(protoKey, currentFileSystem), consumers.assetConsumer);
+      }
     }
 
-    DataKey[] keys = new DataKey[header.getKeyCount()];
-    for (int i = 0; i < header.getKeyCount(); i++) {
-      final SerializeFormat.DataKey proto = SerializeFormat.DataKey.parseDelimitedFrom(in);
-      keys[i] =
-          proto.hasResourceType()
-              ? FullyQualifiedName.fromProto(proto)
-              : RelativeAssetPath.fromProto(proto, currentFileSystem);
-    }
+    // Read back the sources table.
+    DataSourceTable sourceTable = DataSourceTable.read(in, currentFileSystem, header);
 
-    DataSource[] sources = new DataSource[header.getSourceCount()];
-    for (int i = 0; i < header.getSourceCount(); i++) {
-      sources[i] = DataSource.from(ProtoSource.parseDelimitedFrom(in), currentFileSystem);
-    }
-
-    List<SerializeFormat.DataValue> values = new ArrayList<>(header.getValueCount());
-    for (int i = 0; i < header.getValueCount(); i++) {
-      final SerializeFormat.DataValue protoValue = SerializeFormat.DataValue.parseDelimitedFrom(in);
-      if (sources[protoValue.getSourceId()].shouldFilter(filteredResources)) {
+    // TODO(corysmith): Make this a lazy read of the values.
+    for (Entry<DataKey, KeyValueConsumer<DataKey, ?>> entry : keys.entrySet()) {
+      SerializeFormat.DataValue protoValue = SerializeFormat.DataValue.parseDelimitedFrom(in);
+      DataSource source = sourceTable.sourceFromId(protoValue.getSourceId());
+      // Compose the `shortPath` manually to ensure it uses a forward slash.
+      // Using Path.subpath would return a backslash-using path on Windows.
+      String shortPath =
+          source.getPath().getParent().getFileName() + "/" + source.getPath().getFileName();
+      if (filteredResources.contains(shortPath) && !Files.exists(source.getPath())) {
+        // Skip files that were filtered out during analysis.
+        // TODO(asteinb): Properly filter out these files from android_library symbol files during
+        // analysis instead, and remove this list.
         continue;
       }
-      values.add(protoValue);
-    }
-
-    XmlResourceValue[] xml = new XmlResourceValue[header.getXmlCount()];
-    for (int i = 0; i < header.getXmlCount(); i++) {
-      xml[i] =
-          XmlResourceValues.valueFromProto(SerializeFormat.DataValueXml.parseDelimitedFrom(in));
-    }
-
-    Namespaces[] namespaces = new Namespaces[header.getNamespacesCount()];
-    for (int i = 0; i < header.getNamespacesCount(); i++) {
-      final XmlNamespaces proto = XmlNamespaces.parseDelimitedFrom(in);
-      namespaces[i] = Namespaces.fromProto(proto);
-    }
-
-    for (SerializeFormat.DataValue protoValue : values) {
-      final DataSource dataSource =
-          sources[protoValue.getSourceId()].overwrite(
-              protoValue
-                  .getOverwrittenSourceIdList()
-                  .stream()
-                  .map(sourceId -> sources[sourceId])
-                  .collect(Collectors.toList())
-                  .toArray(new DataSource[0]));
-
-      final DataKey dataKey = keys[protoValue.getKeyId()];
-
-      switch (dataKey.getKeyType()) {
-        case ASSET_PATH:
-          consumers.assetConsumer.accept(dataKey, DataValueFile.of(dataSource));
-          break;
-        case FULL_QUALIFIED_NAME:
-          final FullyQualifiedName fullyQualifiedName = (FullyQualifiedName) dataKey;
-
-          KeyValueConsumer<DataKey, DataResource> consumer =
-              fullyQualifiedName.isOverwritable()
-                  ? consumers.overwritingConsumer
-                  : consumers.combiningConsumer;
-
-          if (!protoValue.hasXmlId()) {
-            consumer.accept(dataKey, DataValueFile.of(dataSource));
-          } else {
-            consumer.accept(
-                fullyQualifiedName,
-                protoValue.hasNamespaceId()
-                    ? DataResourceXml.createWithNamespaces(
-                        dataSource,
-                        xml[protoValue.getXmlId()],
-                        namespaces[protoValue.getNamespaceId()])
-                    : DataResourceXml.createWithNoNamespace(
-                        dataSource, xml[protoValue.getXmlId()]));
-          }
-          break;
-        default:
-          throw new DeserializationException("Unknown key type " + dataKey);
+      if (protoValue.hasXmlValue()) {
+        // TODO(corysmith): Figure out why the generics are wrong.
+        // If I use Map<DataKey, KeyValueConsumer<DataKey, ? extends DataValue>>, I can put
+        // consumers into the map, but I can't call accept.
+        // If I use Map<DataKey, KeyValueConsumer<DataKey, ? super DataValue>>, I can consume
+        // but I can't put.
+        // Same for below.
+        @SuppressWarnings("unchecked")
+        KeyValueConsumer<DataKey, DataValue> value =
+            (KeyValueConsumer<DataKey, DataValue>) entry.getValue();
+        value.accept(entry.getKey(), DataResourceXml.from(protoValue, source));
+      } else {
+        @SuppressWarnings("unchecked")
+        KeyValueConsumer<DataKey, DataValue> value =
+            (KeyValueConsumer<DataKey, DataValue>) entry.getValue();
+        value.accept(entry.getKey(), DataValueFile.of(source));
       }
     }
   }
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceParsingAction.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceParsingAction.java
index ce5cb77..e2a98e4 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceParsingAction.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceParsingAction.java
@@ -83,7 +83,7 @@
     logger.fine(String.format("Walked XML tree at %dms", timer.elapsed(TimeUnit.MILLISECONDS)));
     UnwrittenMergedAndroidData unwrittenData =
         UnwrittenMergedAndroidData.of(
-            null, parsedPrimary, ParsedAndroidData.from(ImmutableList.of()));
+            null, parsedPrimary, ParsedAndroidData.from(ImmutableList.<DependencyAndroidData>of()));
     AndroidDataSerializer serializer = AndroidDataSerializer.create();
     unwrittenData.serializeTo(serializer);
     serializer.flushTo(options.output);
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceValidatorAction.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceValidatorAction.java
index 970c7bc..23f1671 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceValidatorAction.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceValidatorAction.java
@@ -162,7 +162,7 @@
           options.packageForR,
           new FlagAaptOptions(aaptConfigOptions),
           aaptConfigOptions.resourceConfigs,
-          ImmutableList.of(),
+          ImmutableList.<String>of(),
           dummyManifest,
           resources,
           assets,
diff --git a/src/tools/android/java/com/google/devtools/build/android/Converters.java b/src/tools/android/java/com/google/devtools/build/android/Converters.java
index 75c5ead..e58dd2d 100644
--- a/src/tools/android/java/com/google/devtools/build/android/Converters.java
+++ b/src/tools/android/java/com/google/devtools/build/android/Converters.java
@@ -218,7 +218,7 @@
     @Override
     public List<DependencySymbolFileProvider> convert(String input) throws OptionsParsingException {
       if (input.isEmpty()) {
-        return ImmutableList.of();
+        return ImmutableList.<DependencySymbolFileProvider>of();
       }
       try {
         ImmutableList.Builder<DependencySymbolFileProvider> builder = ImmutableList.builder();
@@ -473,7 +473,7 @@
 
     @Override
     public List<StaticLibrary> convert(String input) throws OptionsParsingException {
-      final Builder<StaticLibrary> builder = ImmutableList.builder();
+      final Builder<StaticLibrary> builder = ImmutableList.<StaticLibrary>builder();
       for (String path : SPLITTER.splitToList(input)) {
         builder.add(libraryConverter.convert(path));
       }
diff --git a/src/tools/android/java/com/google/devtools/build/android/DataKey.java b/src/tools/android/java/com/google/devtools/build/android/DataKey.java
index f8a76a5..02f193c 100644
--- a/src/tools/android/java/com/google/devtools/build/android/DataKey.java
+++ b/src/tools/android/java/com/google/devtools/build/android/DataKey.java
@@ -13,6 +13,9 @@
 // limitations under the License.
 package com.google.devtools.build.android;
 
+import java.io.IOException;
+import java.io.OutputStream;
+
 /**
  * A general interface for resource and asset keys.
  *
@@ -23,7 +26,16 @@
  *
  * <p>For Assets, it is the asset path from the assets directory.
  */
-public interface DataKey extends Comparable<DataKey>, Writeable {
+public interface DataKey extends Comparable<DataKey> {
+
+  /**
+   * Writes the Key and the value size to a stream.
+   *
+   * @param output The destination stream to serialize the key.
+   * @param valueSize The size, in bytes, of the serialized output for this key. The value size can
+   *     be used for calculating offsets of the value in the stream.
+   */
+  void serializeTo(OutputStream output, int valueSize) throws IOException;
 
   /** Returns a human readable string representation of the key. */
   String toPrettyString();
diff --git a/src/tools/android/java/com/google/devtools/build/android/DataResourceXml.java b/src/tools/android/java/com/google/devtools/build/android/DataResourceXml.java
index eade760..2b39c44 100644
--- a/src/tools/android/java/com/google/devtools/build/android/DataResourceXml.java
+++ b/src/tools/android/java/com/google/devtools/build/android/DataResourceXml.java
@@ -20,11 +20,13 @@
 import com.android.aapt.Resources.Value;
 import com.android.resources.ResourceType;
 import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
-import com.google.devtools.build.android.AndroidDataSerializer.SerializeEntryVisitor;
 import com.google.devtools.build.android.FullyQualifiedName.Factory;
 import com.google.devtools.build.android.FullyQualifiedName.VirtualType;
 import com.google.devtools.build.android.ParsedAndroidData.KeyValueConsumer;
+import com.google.devtools.build.android.proto.SerializeFormat;
+import com.google.devtools.build.android.proto.SerializeFormat.DataValueXml;
 import com.google.devtools.build.android.xml.ArrayXmlResourceValue;
 import com.google.devtools.build.android.xml.AttrXmlResourceValue;
 import com.google.devtools.build.android.xml.IdXmlResourceValue;
@@ -38,6 +40,7 @@
 import com.google.protobuf.InvalidProtocolBufferException;
 import java.io.BufferedInputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -158,6 +161,15 @@
     }
   }
 
+  @SuppressWarnings("deprecation")
+  // TODO(corysmith): Update proto to use get<>Map
+  public static DataValue from(SerializeFormat.DataValue protoValue, DataSource source)
+      throws InvalidProtocolBufferException {
+    DataValueXml xmlValue = protoValue.getXmlValue();
+    return createWithNamespaces(
+        source, valueFromProto(xmlValue), Namespaces.from(xmlValue.getNamespace()));
+  }
+
   public static DataResourceXml from(
       Value protoValue,
       DataSource source,
@@ -172,6 +184,33 @@
     return dataResourceXml;
   }
 
+  private static XmlResourceValue valueFromProto(SerializeFormat.DataValueXml proto)
+      throws InvalidProtocolBufferException {
+    Preconditions.checkArgument(proto.hasType());
+    switch (proto.getType()) {
+      case ARRAY:
+        return ArrayXmlResourceValue.from(proto);
+      case SIMPLE:
+        return SimpleXmlResourceValue.from(proto);
+      case ATTR:
+        return AttrXmlResourceValue.from(proto);
+      case ID:
+        return IdXmlResourceValue.of();
+      case PLURAL:
+        return PluralXmlResourceValue.from(proto);
+      case PUBLIC:
+        return PublicXmlResourceValue.from(proto);
+      case STYLE:
+        return StyleXmlResourceValue.from(proto);
+      case STYLEABLE:
+        return StyleableXmlResourceValue.from(proto);
+      case RESOURCES_ATTRIBUTE:
+        return ResourcesAttribute.from(proto);
+      default:
+        throw new IllegalArgumentException();
+    }
+  }
+
   private static XmlResourceValue valueFromProto(
       Value proto,
       ResourceType resourceType,
@@ -288,7 +327,7 @@
   }
 
   public static DataResourceXml createWithNoNamespace(Path sourcePath, XmlResourceValue xml) {
-    return createWithNamespaces(sourcePath, xml, ImmutableMap.of());
+    return createWithNamespaces(sourcePath, xml, ImmutableMap.<String, String>of());
   }
 
   public static DataResourceXml createWithNoNamespace(DataSource source, XmlResourceValue xml) {
@@ -352,8 +391,9 @@
   }
 
   @Override
-  public SerializeEntryVisitor serializeTo(SerializeEntryVisitor visitor) {
-    return visitor.setXml(xml).setSource(source).setNamespaces(namespaces);
+  public int serializeTo(DataSourceTable sourceTable, OutputStream outStream)
+      throws IOException {
+    return xml.serializeTo(sourceTable.getSourceId(source), namespaces, outStream);
   }
 
   // TODO(corysmith): Clean up all the casting. The type structure is unclean.
diff --git a/src/tools/android/java/com/google/devtools/build/android/DataSource.java b/src/tools/android/java/com/google/devtools/build/android/DataSource.java
index 9949354..16c79d7 100644
--- a/src/tools/android/java/com/google/devtools/build/android/DataSource.java
+++ b/src/tools/android/java/com/google/devtools/build/android/DataSource.java
@@ -17,20 +17,17 @@
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableSet;
-import com.google.devtools.build.android.proto.SerializeFormat;
 import com.google.devtools.build.android.proto.SerializeFormat.ProtoSource;
 import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.nio.file.FileSystem;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.attribute.BasicFileAttributeView;
-import java.util.Set;
 
 /** Represents where the DataValue was derived from. */
-public class DataSource implements Comparable<DataSource>, Writeable {
+public class DataSource implements Comparable<DataSource> {
 
   public static DataSource from(ProtoSource protoSource, FileSystem currentFileSystem) {
     Path path = currentFileSystem.getPath(protoSource.getFilename());
@@ -38,7 +35,7 @@
   }
 
   public static DataSource of(Path sourcePath) {
-    return new DataSource(sourcePath, ImmutableSet.of());
+    return new DataSource(sourcePath, ImmutableSet.<DataSource>of());
   }
 
   private final Path path;
@@ -101,9 +98,6 @@
   }
 
   public DataSource overwrite(DataSource... sources) {
-    if (sources.length == 0) {
-      return this;
-    }
     ImmutableSet.Builder<DataSource> overridesBuilder =
         ImmutableSet.<DataSource>builder().addAll(this.overrides);
     for (DataSource dataSource : sources) {
@@ -143,19 +137,4 @@
   public String asConflictString() {
     return path.toString();
   }
-
-  @Override
-  public void writeTo(OutputStream out) throws IOException {
-    SerializeFormat.ProtoSource.newBuilder()
-        .setFilename(path.toString())
-        .build()
-        .writeDelimitedTo(out);
-  }
-
-  public boolean shouldFilter(Set<String> filteredResources) {
-    return filteredResources.contains(path.getParent().getFileName() + "/" + path.getFileName())
-        // Since the filtered resources short path could match multiple sources, check to make sure
-        // the source doesn't exist.
-        && !Files.exists(path);
-  }
 }
diff --git a/src/tools/android/java/com/google/devtools/build/android/DataSourceTable.java b/src/tools/android/java/com/google/devtools/build/android/DataSourceTable.java
new file mode 100644
index 0000000..ac953da
--- /dev/null
+++ b/src/tools/android/java/com/google/devtools/build/android/DataSourceTable.java
@@ -0,0 +1,131 @@
+// Copyright 2016 The Bazel Authors. All rights reserved.
+//
+// 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.google.devtools.build.android;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.android.proto.SerializeFormat;
+import com.google.devtools.build.android.proto.SerializeFormat.Header;
+import com.google.devtools.build.android.proto.SerializeFormat.ProtoSource;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.FileSystem;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.stream.Collectors;
+
+/**
+ * Tracks mappings from resource source paths (/foo/bar/res/values/colors.xml) to an ID for a more
+ * compact serialization format.
+ */
+class DataSourceTable {
+
+  private static final Function<DataValue, DataSource> VALUE_TO_SOURCE = DataValue::source;
+  private final Map<DataSource, Integer> sourceTable = new LinkedHashMap<>();
+  private DataSource[] idToSource;
+
+  /**
+   * Creates a DataSourceTable and serialize to the given outstream. Assigns each resource source
+   * path a number to enable {@link #getSourceId(DataSource)} queries.
+   *
+   * @param map the final map of resources
+   * @param outStream stream to serialize the source table
+   * @param headerBuilder the header to serialize
+   * @throws IOException if this fails to serialize the table to the outStream
+   */
+  public static DataSourceTable createAndWrite(
+      NavigableMap<DataKey, DataValue> map, OutputStream outStream, Header.Builder headerBuilder)
+      throws IOException {
+    DataSourceTable sourceTable = new DataSourceTable();
+    sourceTable.writeSourceInfo(map, outStream);
+    sourceTable.setHeader(headerBuilder);
+    return sourceTable;
+  }
+
+  /** Convert the absolute source path to the source table index */
+  public int getSourceId(DataSource source) {
+    return sourceTable.get(source);
+  }
+
+  private void writeSourceInfo(NavigableMap<DataKey, DataValue> map, OutputStream outStream)
+      throws IOException {
+    int sourceNumber = 0;
+    LinkedList<DataSource> sourceQueue =
+        map.values()
+            .stream()
+            .map(VALUE_TO_SOURCE)
+            .collect(Collectors.toCollection(LinkedList::new));
+    while (!sourceQueue.isEmpty()) {
+      DataSource source = sourceQueue.pop();
+      if (!sourceTable.containsKey(source)) {
+        sourceTable.put(source, sourceNumber);
+        ++sourceNumber;
+        sourceQueue.addAll(source.overrides());
+      }
+    }
+    for (DataSource dataSource : sourceTable.keySet()) {
+      ProtoSource.newBuilder()
+          .setFilename(dataSource.getPath().toString())
+          .addAllOverwritten(sourcesToIds(dataSource.overrides()))
+          .build()
+          .writeDelimitedTo(outStream);
+    }
+  }
+
+  private List<Integer> sourcesToIds(ImmutableSet<DataSource> overrides) {
+    ImmutableList.Builder<Integer> idsBuilder = ImmutableList.builder();
+    for (DataSource dataSource : overrides) {
+      if (!sourceTable.containsKey(dataSource)) {
+        throw new IllegalArgumentException(
+            "Cannot find data source: " + dataSource.toString() + " in " + sourceTable.keySet());
+      }
+      idsBuilder.add(sourceTable.get(dataSource));
+    }
+    return idsBuilder.build();
+  }
+
+  /** Fill in the serialize format header information required to deserialize */
+  private Header.Builder setHeader(Header.Builder headerBuilder) {
+    return headerBuilder.setSourceCount(sourceTable.size());
+  }
+
+  /** Deserialize the source table and allow {@link #sourceFromId(int)} queries. */
+  public static DataSourceTable read(InputStream in, FileSystem currentFileSystem, Header header)
+      throws IOException {
+    DataSourceTable sourceTable = new DataSourceTable();
+    sourceTable.readSourceInfo(in, currentFileSystem, header);
+    return sourceTable;
+  }
+
+  /** Convert the source ID to full Path */
+  public DataSource sourceFromId(int sourceId) {
+    return idToSource[sourceId];
+  }
+
+  private void readSourceInfo(InputStream in, FileSystem currentFileSystem, Header header)
+      throws IOException {
+    int numberOfSources = header.getSourceCount();
+    // Read back the sources.
+    idToSource = new DataSource[numberOfSources];
+    for (int i = 0; i < numberOfSources; i++) {
+      ProtoSource protoSource = SerializeFormat.ProtoSource.parseDelimitedFrom(in);
+      idToSource[i] = DataSource.from(protoSource, currentFileSystem);
+    }
+  }
+}
diff --git a/src/tools/android/java/com/google/devtools/build/android/DataValue.java b/src/tools/android/java/com/google/devtools/build/android/DataValue.java
index 2a2bc51..de95745 100644
--- a/src/tools/android/java/com/google/devtools/build/android/DataValue.java
+++ b/src/tools/android/java/com/google/devtools/build/android/DataValue.java
@@ -13,8 +13,8 @@
 // limitations under the License.
 package com.google.devtools.build.android;
 
-import com.google.devtools.build.android.AndroidDataSerializer.SerializeEntryVisitor;
 import java.io.IOException;
+import java.io.OutputStream;
 
 /**
  * Represents the value associated with DataKey interface for resource and asset values.
@@ -28,8 +28,9 @@
    */
   DataSource source();
 
-  /** Serializes the value to the entry visitor. */
-  SerializeEntryVisitor serializeTo(SerializeEntryVisitor visitor) throws IOException;
+  /** Serializes to a supplied stream and returns the number of bytes written. */
+  int serializeTo(
+      DataSourceTable sourceTable, OutputStream output) throws IOException;
 
   DataValue update(DataSource source);
 
diff --git a/src/tools/android/java/com/google/devtools/build/android/DataValueFile.java b/src/tools/android/java/com/google/devtools/build/android/DataValueFile.java
index 9a1792f..3270e3c 100644
--- a/src/tools/android/java/com/google/devtools/build/android/DataValueFile.java
+++ b/src/tools/android/java/com/google/devtools/build/android/DataValueFile.java
@@ -14,10 +14,11 @@
 package com.google.devtools.build.android;
 
 import com.google.common.base.MoreObjects;
-import com.google.devtools.build.android.AndroidDataSerializer.SerializeEntryVisitor;
 import com.google.devtools.build.android.AndroidResourceMerger.MergingException;
 import com.google.devtools.build.android.proto.SerializeFormat;
+import com.google.protobuf.CodedOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.nio.file.Path;
 import java.util.Objects;
 
@@ -84,8 +85,13 @@
   }
 
   @Override
-  public SerializeEntryVisitor serializeTo(SerializeEntryVisitor visitor) {
-    return visitor.setSource(source);
+  public int serializeTo(DataSourceTable sourceTable, OutputStream output)
+      throws IOException {
+    SerializeFormat.DataValue.Builder builder = SerializeFormat.DataValue.newBuilder();
+    SerializeFormat.DataValue value = builder.setSourceId(sourceTable.getSourceId(source)).build();
+    value.writeDelimitedTo(output);
+    return CodedOutputStream.computeUInt32SizeNoTag(value.getSerializedSize())
+        + value.getSerializedSize();
   }
 
   @Override
diff --git a/src/tools/android/java/com/google/devtools/build/android/DependencyAndroidData.java b/src/tools/android/java/com/google/devtools/build/android/DependencyAndroidData.java
index 2a77046..b4d4b99 100644
--- a/src/tools/android/java/com/google/devtools/build/android/DependencyAndroidData.java
+++ b/src/tools/android/java/com/google/devtools/build/android/DependencyAndroidData.java
@@ -54,7 +54,7 @@
     // The local symbols.bin is optional -- if it is missing, we'll use the full R.txt
     Path rTxt = exists(fileSystem.getPath(parts[3]));
     ImmutableList<Path> assetDirs =
-        parts[1].length() == 0 ? ImmutableList.of() : splitPaths(parts[1], fileSystem);
+        parts[1].length() == 0 ? ImmutableList.<Path>of() : splitPaths(parts[1], fileSystem);
     CompiledResources compiledSymbols = null;
     Path symbolsBin = null;
 
diff --git a/src/tools/android/java/com/google/devtools/build/android/DeserializationException.java b/src/tools/android/java/com/google/devtools/build/android/DeserializationException.java
index 098f4f5..8c6e599 100644
--- a/src/tools/android/java/com/google/devtools/build/android/DeserializationException.java
+++ b/src/tools/android/java/com/google/devtools/build/android/DeserializationException.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.android;
 
+import java.io.IOException;
 
 /** Thrown when there is an error during deserialization. */
 public class DeserializationException extends RuntimeException {
@@ -29,7 +30,7 @@
     this.isLegacy = false;
   }
 
-  public DeserializationException(Throwable e) {
+  public DeserializationException(IOException e) {
     super(e);
     this.isLegacy = false;
   }
diff --git a/src/tools/android/java/com/google/devtools/build/android/FullyQualifiedName.java b/src/tools/android/java/com/google/devtools/build/android/FullyQualifiedName.java
index d0a5545..9344412 100644
--- a/src/tools/android/java/com/google/devtools/build/android/FullyQualifiedName.java
+++ b/src/tools/android/java/com/google/devtools/build/android/FullyQualifiedName.java
@@ -264,6 +264,11 @@
     return KeyType.FULL_QUALIFIED_NAME;
   }
 
+  @Override
+  public void serializeTo(OutputStream out, int valueSize) throws IOException {
+    toSerializedBuilder().setValueSize(valueSize).build().writeDelimitedTo(out);
+  }
+
   public SerializeFormat.DataKey.Builder toSerializedBuilder() {
     return SerializeFormat.DataKey.newBuilder()
         .setKeyPackage(pkg)
@@ -272,11 +277,6 @@
         .setKeyValue(name);
   }
 
-  @Override
-  public void writeTo(OutputStream out) throws IOException {
-    toSerializedBuilder().build().writeDelimitedTo(out);
-  }
-
   /** The non-resource {@link Type}s of a {@link FullyQualifiedName}. */
   public enum VirtualType implements Type {
     RESOURCES_ATTRIBUTE("<resources>", "Resources Attribute");
@@ -284,7 +284,7 @@
     private final String name;
     private final String displayName;
 
-    VirtualType(String name, String displayName) {
+    private VirtualType(String name, String displayName) {
       this.name = name;
       this.displayName = displayName;
     }
@@ -349,31 +349,31 @@
 
   /** Represents the type of a {@link FullyQualifiedName}. */
   public interface Type {
-    String getName();
+    public String getName();
 
-    ConcreteType getType();
+    public ConcreteType getType();
 
-    boolean isOverwritable(FullyQualifiedName fqn);
+    public boolean isOverwritable(FullyQualifiedName fqn);
 
-    int compareTo(Type other);
+    public int compareTo(Type other);
 
     @Override
-    boolean equals(Object obj);
+    public boolean equals(Object obj);
 
     @Override
-    int hashCode();
+    public int hashCode();
 
     @Override
-    String toString();
+    public String toString();
 
     /**
      * The category of type that a {@link Type} can be.
      *
      * <p><em>Note:</em> used for strict ordering of {@link FullyQualifiedName}s.
      */
-    enum ConcreteType {
+    public enum ConcreteType {
       RESOURCE_TYPE,
-      VIRTUAL_TYPE
+      VIRTUAL_TYPE;
     }
   }
 
@@ -511,7 +511,7 @@
 
       // This is fragile but better than the Gradle scheme of just dropping
       // entire subtrees.
-      Builder<String> builder = ImmutableList.builder();
+      Builder<String> builder = ImmutableList.<String>builder();
       addIfNotNull(config.getCountryCodeQualifier(), builder);
       addIfNotNull(config.getNetworkCodeQualifier(), builder);
       if (transformedLocaleQualifiers.isEmpty()) {
diff --git a/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java b/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java
index b8249dc..a7301f1 100644
--- a/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java
+++ b/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java
@@ -41,6 +41,7 @@
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerConfigurationException;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.TransformerFactoryConfigurationError;
@@ -161,8 +162,8 @@
   private static Options options;
 
   private static Path removePermissions(Path manifest, Path outputDir)
-      throws IOException, ParserConfigurationException, TransformerException,
-          TransformerFactoryConfigurationError, SAXException {
+      throws IOException, ParserConfigurationException, TransformerConfigurationException,
+          TransformerException, TransformerFactoryConfigurationError, SAXException {
     DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
     Document doc = docBuilder.parse(manifest.toFile());
     for (String tag : PERMISSION_TAGS) {
diff --git a/src/tools/android/java/com/google/devtools/build/android/PlaceholderIdFieldInitializerBuilder.java b/src/tools/android/java/com/google/devtools/build/android/PlaceholderIdFieldInitializerBuilder.java
index ee16633..12b7abe 100644
--- a/src/tools/android/java/com/google/devtools/build/android/PlaceholderIdFieldInitializerBuilder.java
+++ b/src/tools/android/java/com/google/devtools/build/android/PlaceholderIdFieldInitializerBuilder.java
@@ -453,7 +453,7 @@
       // The styleable array should be sorted by ID value.
       // Make sure that if we have android: framework attributes, their IDs are listed first.
       ImmutableMap<String, Integer> arrayInitMap =
-          arrayInitValues.orderEntriesByValue(Ordering.natural()).build();
+          arrayInitValues.orderEntriesByValue(Ordering.<Integer>natural()).build();
       initList.put(field, IntArrayFieldInitializer.of(arrayInitMap.values()));
       int index = 0;
       for (String attr : arrayInitMap.keySet()) {
diff --git a/src/tools/android/java/com/google/devtools/build/android/RelativeAssetPath.java b/src/tools/android/java/com/google/devtools/build/android/RelativeAssetPath.java
index fa51742..1801026 100644
--- a/src/tools/android/java/com/google/devtools/build/android/RelativeAssetPath.java
+++ b/src/tools/android/java/com/google/devtools/build/android/RelativeAssetPath.java
@@ -32,7 +32,6 @@
  * <p>Note: Assets have no qualifiers or packages.
  */
 public class RelativeAssetPath implements DataKey {
-
   /** A Factory that creates RelativeAssetsPath objects whose paths are relative to a given path. */
   public static class Factory {
     private final Path assetRoot;
@@ -111,11 +110,12 @@
   }
 
   @Override
-  public void writeTo(OutputStream out) throws IOException {
+  public void serializeTo(OutputStream output, int valueSize) throws IOException {
     SerializeFormat.DataKey.newBuilder()
         .setKeyValue(relativeAssetPath.toString())
+        .setValueSize(valueSize)
         .build()
-        .writeDelimitedTo(out);
+        .writeDelimitedTo(output);
   }
 
   @Override
diff --git a/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox.java b/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox.java
index cb1f43c..a99da9b 100644
--- a/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox.java
+++ b/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox.java
@@ -54,7 +54,7 @@
  * </pre>
  */
 public class ResourceProcessorBusyBox {
-  enum Tool {
+  static enum Tool {
     PACKAGE() {
       @Override
       void call(String[] args) throws Exception {
diff --git a/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java b/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java
index bb68ef7..7d9f59f 100644
--- a/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java
+++ b/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java
@@ -325,7 +325,7 @@
           aaptConfigOptions.splits,
           new MergedAndroidData(
               shrunkResources, resourceFiles.resolve("assets"), options.primaryManifest),
-          ImmutableList.of() /* libraries */,
+          ImmutableList.<DependencyAndroidData>of() /* libraries */,
           generatedSources,
           options.shrunkApk,
           null /* proguardOutput */,
diff --git a/src/tools/android/java/com/google/devtools/build/android/UnvalidatedAndroidDirectories.java b/src/tools/android/java/com/google/devtools/build/android/UnvalidatedAndroidDirectories.java
index 7aa3164..49fdb18 100644
--- a/src/tools/android/java/com/google/devtools/build/android/UnvalidatedAndroidDirectories.java
+++ b/src/tools/android/java/com/google/devtools/build/android/UnvalidatedAndroidDirectories.java
@@ -41,8 +41,8 @@
     }
     String[] parts = text.split(":");
     return new UnvalidatedAndroidDirectories(
-        parts.length > 0 ? splitPaths(parts[0], fileSystem) : ImmutableList.of(),
-        parts.length > 1 ? splitPaths(parts[1], fileSystem) : ImmutableList.of());
+        parts.length > 0 ? splitPaths(parts[0], fileSystem) : ImmutableList.<Path>of(),
+        parts.length > 1 ? splitPaths(parts[1], fileSystem) : ImmutableList.<Path>of());
   }
 
   protected static ImmutableList<Path> splitPaths(String pathsString, FileSystem fileSystem) {
diff --git a/src/tools/android/java/com/google/devtools/build/android/Writeable.java b/src/tools/android/java/com/google/devtools/build/android/Writeable.java
deleted file mode 100644
index d1ef46d..0000000
--- a/src/tools/android/java/com/google/devtools/build/android/Writeable.java
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2018 The Bazel Authors. All rights reserved.
-//
-// 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.google.devtools.build.android;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-/** Common interface for serialization using the {@link AndroidDataSerializer}. */
-public interface Writeable {
-  /** Writes the current state to the {@link OutputStream}. */
-  void writeTo(OutputStream out) throws IOException;
-}
diff --git a/src/tools/android/java/com/google/devtools/build/android/XmlResourceValue.java b/src/tools/android/java/com/google/devtools/build/android/XmlResourceValue.java
index e8cab89..f24d6b2 100644
--- a/src/tools/android/java/com/google/devtools/build/android/XmlResourceValue.java
+++ b/src/tools/android/java/com/google/devtools/build/android/XmlResourceValue.java
@@ -13,8 +13,12 @@
 // limitations under the License.
 package com.google.devtools.build.android;
 
+import com.google.devtools.build.android.xml.Namespaces;
+import java.io.IOException;
+import java.io.OutputStream;
+
 /** An {@link XmlResourceValue} is extracted from xml files in the resource 'values' directory. */
-public interface XmlResourceValue extends Writeable {
+public interface XmlResourceValue {
   /**
    * Each XmlValue is expected to write a valid representation in xml to the writer.
    *
@@ -24,6 +28,9 @@
    */
   void write(FullyQualifiedName key, DataSource source, AndroidDataWritingVisitor mergedDataWriter);
 
+  /** Serializes the resource value to the OutputStream and returns the bytes written. */
+  int serializeTo(int sourceId, Namespaces namespaces, OutputStream out) throws IOException;
+
   /**
    * Combines these xml values together and returns a single value.
    *
diff --git a/src/tools/android/java/com/google/devtools/build/android/XmlResourceValues.java b/src/tools/android/java/com/google/devtools/build/android/XmlResourceValues.java
index 20df222..1ea3882 100644
--- a/src/tools/android/java/com/google/devtools/build/android/XmlResourceValues.java
+++ b/src/tools/android/java/com/google/devtools/build/android/XmlResourceValues.java
@@ -20,18 +20,15 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.android.ParsedAndroidData.KeyValueConsumer;
 import com.google.devtools.build.android.proto.SerializeFormat;
-import com.google.devtools.build.android.xml.ArrayXmlResourceValue;
 import com.google.devtools.build.android.xml.AttrXmlResourceValue;
 import com.google.devtools.build.android.xml.IdXmlResourceValue;
 import com.google.devtools.build.android.xml.Namespaces;
 import com.google.devtools.build.android.xml.PluralXmlResourceValue;
 import com.google.devtools.build.android.xml.PublicXmlResourceValue;
-import com.google.devtools.build.android.xml.ResourcesAttribute;
 import com.google.devtools.build.android.xml.SimpleXmlResourceValue;
 import com.google.devtools.build.android.xml.StyleXmlResourceValue;
 import com.google.devtools.build.android.xml.StyleableXmlResourceValue;
 import com.google.protobuf.CodedOutputStream;
-import com.google.protobuf.InvalidProtocolBufferException;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.StringWriter;
@@ -446,35 +443,4 @@
   public static boolean isSkip(StartElement start) {
     return isTag(start, TAG_SKIP);
   }
-
-  /** Creates the value from a proto. */
-  public static XmlResourceValue valueFromProto(SerializeFormat.DataValueXml proto) {
-    try {
-      Preconditions.checkArgument(proto.hasType());
-      switch (proto.getType()) {
-        case ARRAY:
-          return ArrayXmlResourceValue.from(proto);
-        case SIMPLE:
-          return SimpleXmlResourceValue.from(proto);
-        case ATTR:
-          return AttrXmlResourceValue.from(proto);
-        case ID:
-          return IdXmlResourceValue.of();
-        case PLURAL:
-          return PluralXmlResourceValue.from(proto);
-        case PUBLIC:
-          return PublicXmlResourceValue.from(proto);
-        case STYLE:
-          return StyleXmlResourceValue.from(proto);
-        case STYLEABLE:
-          return StyleableXmlResourceValue.from(proto);
-        case RESOURCES_ATTRIBUTE:
-          return ResourcesAttribute.from(proto);
-        default:
-          throw new IllegalArgumentException();
-      }
-    } catch (InvalidProtocolBufferException e) {
-      throw new DeserializationException(e);
-    }
-  }
 }
diff --git a/src/tools/android/java/com/google/devtools/build/android/proto/serialize_format.proto b/src/tools/android/java/com/google/devtools/build/android/proto/serialize_format.proto
index 9412cea..b87d5fe 100644
--- a/src/tools/android/java/com/google/devtools/build/android/proto/serialize_format.proto
+++ b/src/tools/android/java/com/google/devtools/build/android/proto/serialize_format.proto
@@ -24,29 +24,25 @@
 // See com.google.devtools.build.android.AndroidDataSerializer for details on
 // how these messages are used.
 message Header {
+  // The number of entries stored in a serialized buffer.
+  optional uint32 entry_count = 1;
   // The number of ProtoSource entries.
-  optional uint32 source_count = 1;
-  // The number of keys in the serialized buffer.
-  optional uint32 key_count = 2;
-  // The number of values in the serialized buffer.
-  optional uint32 value_count = 3;
-  // The number of xml definitions in the serialized buffer.
-  optional uint32 xml_count = 4;
-  // The number of xml namespace definitions in the serialized buffer.
-  optional uint32 namespaces_count = 5;
+  optional uint32 source_count = 2;
 }
 
 // The serialized format for a DataKey.
 message DataKey {
   // Used for both the FullyQualifiedName name and RelativeAssetPath path
-  // Required
-  optional string key_value = 1;
+  optional string key_value = 2;
   // The resource type for FullyQualifiedNames
-  optional string resource_type = 2;
-  optional string key_package = 3;
-  repeated string qualifiers = 4;
+  optional string resource_type = 3;
+  optional string key_package = 4;
+  repeated string qualifiers = 5;
+  // The size of the associated value. Useful for calculating an offset.
+  // Required
+  optional int32 value_size = 6;
   // Whether this DataKey is a reference to another DataKey.
-  optional bool reference = 5;
+  optional bool reference = 7;
 }
 
 // The serialized format for a DataValue.
@@ -55,41 +51,30 @@
   // Required
   optional uint32 source_id = 1;
 
-  // Index of stored xml value
-  optional uint32 xml_id = 2;
-
-  // Index of stored key.
-  // Required
-  optional uint32 key_id = 3;
-
-  // Sources that have been overwritten.
-  repeated uint32 overwritten_source_id = 4;
-
-  optional uint32 namespace_id = 5;
+  // If xml_value is defined it's an xml value, otherwise, it's a file value.
+  optional DataValueXml xml_value= 2;
 }
 
 // A container for all the source information to be persisted.
 message ProtoSource {
   // Required
   optional string filename = 1;
-}
-
-message XmlNamespaces {
-  map<string, string> namespace = 1;
+  // The indexes of sources this source replaces.
+  repeated uint32 overwritten = 2;
 }
 
 // The container for a serialized xml value.
 message DataValueXml {
   enum XmlType {
-    ARRAY = 1;
-    ATTR = 2;
-    ID = 3;
-    PLURAL = 4;
-    PUBLIC = 5;
-    SIMPLE = 6;
-    STYLEABLE = 7;
-    STYLE = 8;
-    RESOURCES_ATTRIBUTE = 9;
+    ARRAY = 0;
+    ATTR = 1;
+    ID = 2;
+    PLURAL = 3;
+    PUBLIC = 4;
+    SIMPLE = 5;
+    STYLEABLE = 6;
+    STYLE = 7;
+    RESOURCES_ATTRIBUTE = 8;
   }
 
   optional XmlType type = 1;
@@ -100,4 +85,5 @@
   optional string value_type = 6;
   repeated DataKey references = 7;
   map<string, string> attribute = 8;
+  map<string, string> namespace = 9;
 }
diff --git a/src/tools/android/java/com/google/devtools/build/android/xml/ArrayXmlResourceValue.java b/src/tools/android/java/com/google/devtools/build/android/xml/ArrayXmlResourceValue.java
index f977c7b..fb74fd2 100644
--- a/src/tools/android/java/com/google/devtools/build/android/xml/ArrayXmlResourceValue.java
+++ b/src/tools/android/java/com/google/devtools/build/android/xml/ArrayXmlResourceValue.java
@@ -29,8 +29,6 @@
 import com.google.devtools.build.android.XmlResourceValue;
 import com.google.devtools.build.android.XmlResourceValues;
 import com.google.devtools.build.android.proto.SerializeFormat;
-import com.google.devtools.build.android.proto.SerializeFormat.DataValueXml;
-import com.google.devtools.build.android.proto.SerializeFormat.DataValueXml.XmlType;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.ArrayList;
@@ -47,15 +45,14 @@
 /**
  * Represents an Android resource array.
  *
- * <p>There are two flavors of Android Resource arrays:
- *
+ * There are two flavors of Android Resource arrays:
  * <ul>
- *   <li>Typed arrays (http://developer.android.com/guide/topics/resources/more-resources
- *       .html#TypedArray) which which are indicated by a &lt;array&gt; tag.
- *   <li>Integer array (http://developer.android.com/guide/topics/resources/more-resources
- *       .html#IntegerArray) which are indicated by &lt;integer-array&gt; tag.
- *   <li>String array (http://developer.android.com/guide/topics/resources/string-resource
- *       .html#StringArray) which are indicated by &lt;string-array&gt; tag.
+ * <li>Typed arrays (http://developer.android.com/guide/topics/resources/more-resources
+ * .html#TypedArray) which which are indicated by a &lt;array&gt; tag.</li>
+ * <li>Integer array (http://developer.android.com/guide/topics/resources/more-resources
+ * .html#IntegerArray) which are indicated by &lt;integer-array&gt; tag.</li>
+ * <li>String array (http://developer.android.com/guide/topics/resources/string-resource
+ * .html#StringArray) which are indicated by &lt;string-array&gt; tag.</li>
  * </ul>
  *
  * Both of these are accessed by R.array.&lt;name&gt; in java.
@@ -65,19 +62,9 @@
   private static final QName TAG_INTEGER_ARRAY = QName.valueOf("integer-array");
   private static final QName TAG_ARRAY = QName.valueOf("array");
   private static final QName TAG_STRING_ARRAY = QName.valueOf("string-array");
-
-  @Override
-  public void writeTo(OutputStream out) throws IOException {
-    DataValueXml.newBuilder()
-        .addAllListValue(values)
-        .setType(XmlType.ARRAY)
-        .putAllAttribute(attributes)
-        .setValueType(arrayType.toString())
-        .build()
-        .writeDelimitedTo(out);
-  }
-
-  /** Enumerates the different types of array parentTags. */
+  /**
+   * Enumerates the different types of array parentTags.
+   */
   public enum ArrayType {
     INTEGER_ARRAY(TAG_INTEGER_ARRAY),
     ARRAY(TAG_ARRAY),
@@ -118,7 +105,7 @@
   }
 
   public static XmlResourceValue of(ArrayType arrayType, List<String> values) {
-    return of(arrayType, values, ImmutableMap.of());
+    return of(arrayType, values, ImmutableMap.<String, String>of());
   }
 
   public static XmlResourceValue of(
@@ -151,20 +138,20 @@
       }
     }
 
-    return of(ArrayType.ARRAY, items, ImmutableMap.of());
+    return of(
+        ArrayType.ARRAY,
+        items,
+        ImmutableMap.of());
   }
 
   @Override
   public void write(
       FullyQualifiedName key, DataSource source, AndroidDataWritingVisitor mergedDataWriter) {
-    ValuesResourceDefinition definition =
-        mergedDataWriter
-            .define(key)
-            .derivedFrom(source)
-            .startTag(arrayType.tagName)
-            .named(key)
-            .addAttributesFrom(attributes.entrySet())
-            .closeTag();
+    ValuesResourceDefinition definition = mergedDataWriter.define(key).derivedFrom(source)
+        .startTag(arrayType.tagName)
+        .named(key)
+        .addAttributesFrom(attributes.entrySet())
+        .closeTag();
     for (String value : values) {
       definition =
           definition
@@ -178,6 +165,21 @@
   }
 
   @Override
+  public int serializeTo(int sourceId, Namespaces namespaces, OutputStream output)
+      throws IOException {
+    return XmlResourceValues.serializeProtoDataValue(
+        output,
+        XmlResourceValues.newSerializableDataValueBuilder(sourceId)
+            .setXmlValue(
+                SerializeFormat.DataValueXml.newBuilder()
+                    .addAllListValue(values)
+                    .setType(SerializeFormat.DataValueXml.XmlType.ARRAY)
+                    .putAllNamespace(namespaces.asMap())
+                    .putAllAttribute(attributes)
+                    .setValueType(arrayType.toString())));
+  }
+
+  @Override
   public int hashCode() {
     return Objects.hash(arrayType, values, attributes);
   }
diff --git a/src/tools/android/java/com/google/devtools/build/android/xml/AttrXmlResourceValue.java b/src/tools/android/java/com/google/devtools/build/android/xml/AttrXmlResourceValue.java
index 96ac31c..f2645ac 100644
--- a/src/tools/android/java/com/google/devtools/build/android/xml/AttrXmlResourceValue.java
+++ b/src/tools/android/java/com/google/devtools/build/android/xml/AttrXmlResourceValue.java
@@ -404,16 +404,23 @@
     }
   }
 
+  @SuppressWarnings("deprecation")
   @Override
-  public void writeTo(OutputStream out) throws IOException {
+  public int serializeTo(int sourceId, Namespaces namespaces, OutputStream output)
+      throws IOException {
+    SerializeFormat.DataValue.Builder builder =
+        XmlResourceValues.newSerializableDataValueBuilder(sourceId);
     SerializeFormat.DataValueXml.Builder xmlValueBuilder =
         SerializeFormat.DataValueXml.newBuilder();
-    xmlValueBuilder.setType(SerializeFormat.DataValueXml.XmlType.ATTR);
+    xmlValueBuilder
+        .setType(SerializeFormat.DataValueXml.XmlType.ATTR)
+        .putAllNamespace(namespaces.asMap());
     for (Entry<String, ResourceXmlAttrValue> entry : formats.entrySet()) {
       xmlValueBuilder.putMappedXmlValue(
-          entry.getKey(), entry.getValue().appendTo(SerializeFormat.DataValueXml.newBuilder()));
+          entry.getKey(), entry.getValue().appendTo(builder.getXmlValueBuilder()));
     }
-    xmlValueBuilder.build().writeDelimitedTo(out);
+    builder.setXmlValue(xmlValueBuilder);
+    return XmlResourceValues.serializeProtoDataValue(output, builder);
   }
 
   @Override
diff --git a/src/tools/android/java/com/google/devtools/build/android/xml/IdXmlResourceValue.java b/src/tools/android/java/com/google/devtools/build/android/xml/IdXmlResourceValue.java
index e3fe65a..c3fb2fa 100644
--- a/src/tools/android/java/com/google/devtools/build/android/xml/IdXmlResourceValue.java
+++ b/src/tools/android/java/com/google/devtools/build/android/xml/IdXmlResourceValue.java
@@ -20,8 +20,11 @@
 import com.google.devtools.build.android.DataSource;
 import com.google.devtools.build.android.FullyQualifiedName;
 import com.google.devtools.build.android.XmlResourceValue;
+import com.google.devtools.build.android.XmlResourceValues;
 import com.google.devtools.build.android.proto.SerializeFormat;
+import com.google.devtools.build.android.proto.SerializeFormat.DataValueXml.Builder;
 import com.google.devtools.build.android.proto.SerializeFormat.DataValueXml.XmlType;
+import com.google.protobuf.CodedOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.Objects;
@@ -91,8 +94,20 @@
   }
 
   @Override
-  public void writeTo(OutputStream out) throws IOException {
-    SerializeFormat.DataValueXml.newBuilder().setType(XmlType.ID).build().writeDelimitedTo(out);
+  public int serializeTo(int sourceId, Namespaces namespaces, OutputStream output)
+      throws IOException {
+    Builder xmlValue =
+        SerializeFormat.DataValueXml.newBuilder()
+            .setType(XmlType.ID)
+            .putAllNamespace(namespaces.asMap());
+    if (value != null) {
+      xmlValue.setValue(value);
+    }
+    SerializeFormat.DataValue dataValue =
+        XmlResourceValues.newSerializableDataValueBuilder(sourceId).setXmlValue(xmlValue).build();
+    dataValue.writeDelimitedTo(output);
+    return CodedOutputStream.computeUInt32SizeNoTag(dataValue.getSerializedSize())
+        + dataValue.getSerializedSize();
   }
 
   @Override
diff --git a/src/tools/android/java/com/google/devtools/build/android/xml/Namespaces.java b/src/tools/android/java/com/google/devtools/build/android/xml/Namespaces.java
index 10da5ff..82e8810 100644
--- a/src/tools/android/java/com/google/devtools/build/android/xml/Namespaces.java
+++ b/src/tools/android/java/com/google/devtools/build/android/xml/Namespaces.java
@@ -16,13 +16,8 @@
 import com.google.common.base.MoreObjects;
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.android.DataResourceXml;
-import com.google.devtools.build.android.Writeable;
 import com.google.devtools.build.android.XmlResourceValue;
 import com.google.devtools.build.android.XmlResourceValues;
-import com.google.devtools.build.android.proto.SerializeFormat;
-import com.google.devtools.build.android.proto.SerializeFormat.XmlNamespaces;
-import java.io.IOException;
-import java.io.OutputStream;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -44,23 +39,11 @@
  * resources tag to combining multiple {@link DataResourceXml}s, the Namespaces must be tracked and
  * kept with each value.
  */
-public class Namespaces implements Iterable<Entry<String, String>>, Writeable {
+public class Namespaces implements Iterable<Entry<String, String>> {
   private static final Logger logger = Logger.getLogger(Namespaces.class.getCanonicalName());
   private static final Namespaces EMPTY_INSTANCE =
       new Namespaces(ImmutableMap.<String, String>of());
 
-  @Override
-  public void writeTo(OutputStream out) throws IOException {
-    SerializeFormat.XmlNamespaces.newBuilder()
-        .putAllNamespace(prefixToUri)
-        .build()
-        .writeDelimitedTo(out);
-  }
-
-  public static Namespaces fromProto(XmlNamespaces xmlNamespaces) {
-    return from(xmlNamespaces.getNamespaceMap());
-  }
-
   /** Collects prefix and uri pairs from elements. */
   public static class Collector {
     private Map<String, String> prefixToUri = new HashMap<>();
diff --git a/src/tools/android/java/com/google/devtools/build/android/xml/PluralXmlResourceValue.java b/src/tools/android/java/com/google/devtools/build/android/xml/PluralXmlResourceValue.java
index 7c1b653..b912cc1 100644
--- a/src/tools/android/java/com/google/devtools/build/android/xml/PluralXmlResourceValue.java
+++ b/src/tools/android/java/com/google/devtools/build/android/xml/PluralXmlResourceValue.java
@@ -24,8 +24,10 @@
 import com.google.devtools.build.android.DataSource;
 import com.google.devtools.build.android.FullyQualifiedName;
 import com.google.devtools.build.android.XmlResourceValue;
+import com.google.devtools.build.android.XmlResourceValues;
 import com.google.devtools.build.android.proto.SerializeFormat;
 import com.google.devtools.build.android.proto.SerializeFormat.DataValueXml.XmlType;
+import com.google.protobuf.CodedOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.HashMap;
@@ -155,13 +157,23 @@
   }
 
   @Override
-  public void writeTo(OutputStream out) throws IOException {
-    SerializeFormat.DataValueXml.newBuilder()
-        .setType(XmlType.PLURAL)
-        .putAllAttribute(attributes)
-        .putAllMappedStringValue(values)
-        .build()
-        .writeDelimitedTo(out);
+  public int serializeTo(int sourceId, Namespaces namespaces, OutputStream output)
+      throws IOException {
+    SerializeFormat.DataValue.Builder builder =
+        XmlResourceValues.newSerializableDataValueBuilder(sourceId);
+    SerializeFormat.DataValue value =
+        builder
+            .setXmlValue(
+                builder
+                    .getXmlValueBuilder()
+                    .setType(XmlType.PLURAL)
+                    .putAllNamespace(namespaces.asMap())
+                    .putAllAttribute(attributes)
+                    .putAllMappedStringValue(values))
+            .build();
+    value.writeDelimitedTo(output);
+    return CodedOutputStream.computeUInt32SizeNoTag(value.getSerializedSize())
+        + value.getSerializedSize();
   }
 
   @Override
diff --git a/src/tools/android/java/com/google/devtools/build/android/xml/PublicXmlResourceValue.java b/src/tools/android/java/com/google/devtools/build/android/xml/PublicXmlResourceValue.java
index c1e3eb4..af4184d 100644
--- a/src/tools/android/java/com/google/devtools/build/android/xml/PublicXmlResourceValue.java
+++ b/src/tools/android/java/com/google/devtools/build/android/xml/PublicXmlResourceValue.java
@@ -19,11 +19,13 @@
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
 import com.google.devtools.build.android.AndroidDataWritingVisitor;
 import com.google.devtools.build.android.AndroidResourceSymbolSink;
 import com.google.devtools.build.android.DataSource;
 import com.google.devtools.build.android.FullyQualifiedName;
 import com.google.devtools.build.android.XmlResourceValue;
+import com.google.devtools.build.android.XmlResourceValues;
 import com.google.devtools.build.android.proto.SerializeFormat;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -31,7 +33,6 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
-import java.util.stream.Collectors;
 
 /**
  * Represents an Android resource &lt;public&gt; xml tag.
@@ -138,19 +139,23 @@
   }
 
   @Override
-  public void writeTo(OutputStream out) throws IOException {
-    SerializeFormat.DataValueXml.newBuilder()
-        .setType(SerializeFormat.DataValueXml.XmlType.PUBLIC)
-        .putAllMappedStringValue(
-            typeToId
-                .entrySet()
-                .stream()
-                .collect(
-                    Collectors.toMap(
-                        e -> e.getKey().toString(),
-                        e -> e.getValue().transform(Object::toString).or(MISSING_ID_VALUE))))
-        .build()
-        .writeDelimitedTo(out);
+  public int serializeTo(int sourceId, Namespaces namespaces, OutputStream output)
+      throws IOException {
+    Map<String, String> assignments = Maps.newLinkedHashMapWithExpectedSize(typeToId.size());
+    for (Entry<ResourceType, Optional<Integer>> entry : typeToId.entrySet()) {
+      Optional<Integer> value = entry.getValue();
+      String stringValue = value.isPresent() ? value.get().toString() : MISSING_ID_VALUE;
+      assignments.put(entry.getKey().toString(), stringValue);
+    }
+    SerializeFormat.DataValue.Builder builder =
+        XmlResourceValues.newSerializableDataValueBuilder(sourceId);
+    builder.setXmlValue(
+        builder
+            .getXmlValueBuilder()
+            .setType(SerializeFormat.DataValueXml.XmlType.PUBLIC)
+            .putAllNamespace(namespaces.asMap())
+            .putAllMappedStringValue(assignments));
+    return XmlResourceValues.serializeProtoDataValue(output, builder);
   }
 
   @Override
@@ -173,7 +178,7 @@
     }
     return of(combined);
   }
-
+  
   @Override
   public String asConflictStringWith(DataSource source) {
     return source.asConflictString();
diff --git a/src/tools/android/java/com/google/devtools/build/android/xml/ResourcesAttribute.java b/src/tools/android/java/com/google/devtools/build/android/xml/ResourcesAttribute.java
index 75a6c02..a54667e 100644
--- a/src/tools/android/java/com/google/devtools/build/android/xml/ResourcesAttribute.java
+++ b/src/tools/android/java/com/google/devtools/build/android/xml/ResourcesAttribute.java
@@ -21,7 +21,9 @@
 import com.google.devtools.build.android.DataSource;
 import com.google.devtools.build.android.FullyQualifiedName;
 import com.google.devtools.build.android.XmlResourceValue;
+import com.google.devtools.build.android.XmlResourceValues;
 import com.google.devtools.build.android.proto.SerializeFormat;
+import com.google.devtools.build.android.proto.SerializeFormat.DataValueXml.Builder;
 import com.google.errorprone.annotations.Immutable;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -38,15 +40,13 @@
     public String combine(String first, String second);
   }
 
-  private static final Combiner COMMA_SEPARATED_COMBINER =
-      new Combiner() {
-        private final Joiner joiner = Joiner.on(',');
-
-        @Override
-        public String combine(String first, String second) {
-          return joiner.join(first, second);
-        }
-      };
+  private static final Combiner COMMA_SEPARATED_COMBINER = new Combiner() {
+    private final Joiner joiner = Joiner.on(',');
+    @Override
+    public String combine(String first, String second) {
+      return joiner.join(first, second);
+    }
+  };
 
   /**
    * Represents the semantic meaning of an xml attribute and how it is combined with other
@@ -92,7 +92,9 @@
     Map.Entry<String, String> attribute =
         Iterables.getOnlyElement(proto.getAttributeMap().entrySet());
     return new ResourcesAttribute(
-        AttributeType.valueOf(proto.getValueType()), attribute.getKey(), attribute.getValue());
+        AttributeType.valueOf(proto.getValueType()),
+        attribute.getKey(),
+        attribute.getValue());
   }
 
   private final AttributeType type;
@@ -112,13 +114,19 @@
   }
 
   @Override
-  public void writeTo(OutputStream out) throws IOException {
-    SerializeFormat.DataValueXml.newBuilder()
-        .setType(SerializeFormat.DataValueXml.XmlType.RESOURCES_ATTRIBUTE)
-        .setValueType(type.name())
-        .putAttribute(name, value)
-        .build()
-        .writeDelimitedTo(out);
+  public int serializeTo(int sourceId, Namespaces namespaces, OutputStream output)
+      throws IOException {
+    SerializeFormat.DataValue.Builder builder =
+        XmlResourceValues.newSerializableDataValueBuilder(sourceId);
+    Builder xmlValueBuilder =
+        builder
+            .getXmlValueBuilder()
+            .putAllNamespace(namespaces.asMap())
+            .setType(SerializeFormat.DataValueXml.XmlType.RESOURCES_ATTRIBUTE)
+            .setValueType(type.name())
+            .putAttribute(name, value);
+    builder.setXmlValue(xmlValueBuilder);
+    return XmlResourceValues.serializeProtoDataValue(output, builder);
   }
 
   @Override
diff --git a/src/tools/android/java/com/google/devtools/build/android/xml/SimpleXmlResourceValue.java b/src/tools/android/java/com/google/devtools/build/android/xml/SimpleXmlResourceValue.java
index 55bef85..32147cd 100644
--- a/src/tools/android/java/com/google/devtools/build/android/xml/SimpleXmlResourceValue.java
+++ b/src/tools/android/java/com/google/devtools/build/android/xml/SimpleXmlResourceValue.java
@@ -27,10 +27,9 @@
 import com.google.devtools.build.android.DataSource;
 import com.google.devtools.build.android.FullyQualifiedName;
 import com.google.devtools.build.android.XmlResourceValue;
+import com.google.devtools.build.android.XmlResourceValues;
 import com.google.devtools.build.android.proto.SerializeFormat;
-import com.google.devtools.build.android.proto.SerializeFormat.DataValueXml;
 import com.google.devtools.build.android.proto.SerializeFormat.DataValueXml.Builder;
-import com.google.devtools.build.android.proto.SerializeFormat.DataValueXml.XmlType;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.Arrays;
@@ -42,7 +41,8 @@
 /**
  * Represents a simple Android resource xml value.
  *
- * <p>There is a class of resources that are simple name/value pairs: string
+ * <p>
+ * There is a class of resources that are simple name/value pairs: string
  * (http://developer.android.com/guide/topics/resources/string-resource.html), bool
  * (http://developer.android.com/guide/topics/resources/more-resources.html#Bool), color
  * (http://developer.android.com/guide/topics/resources/more-resources.html#Color), and dimen
@@ -66,27 +66,106 @@
   static final QName TAG_RAW = QName.valueOf("raw");
   static final QName TAG_STRING = QName.valueOf("string");
 
-  /** Provides an enumeration resource type. */
+  /** Provides an enumeration resource type and simple value validation. */
   public enum Type {
-    BOOL(TAG_BOOL),
-    COLOR(TAG_COLOR),
-    DIMEN(TAG_DIMEN),
-    DRAWABLE(TAG_DRAWABLE),
-    FRACTION(TAG_FRACTION),
-    INTEGER(TAG_INTEGER),
-    ITEM(TAG_ITEM),
-    LAYOUT(TAG_LAYOUT),
-    MENU(TAG_MENU),
-    MIPMAP(TAG_MIPMAP),
-    PUBLIC(TAG_PUBLIC),
-    RAW(TAG_RAW),
-    STRING(TAG_STRING);
+    BOOL(TAG_BOOL) {
+      @Override
+      public boolean validate(String value) {
+        final String cleanValue = value.toLowerCase().trim();
+        return "true".equals(cleanValue) || "false".equals(cleanValue);
+      }
+    },
+    COLOR(TAG_COLOR) {
+      @Override
+      public boolean validate(String value) {
+        // TODO(corysmith): Validate the hex color.
+        return true;
+      }
+    },
+    DIMEN(TAG_DIMEN) {
+      @Override
+      public boolean validate(String value) {
+        // TODO(corysmith): Validate the dimension type.
+        return true;
+      }
+    },
+    DRAWABLE(TAG_DRAWABLE) {
+      @Override
+      public boolean validate(String value) {
+        // TODO(corysmith): Validate the drawable type.
+        return true;
+      }
+    },
+    FRACTION(TAG_FRACTION) {
+      @Override
+      public boolean validate(String value) {
+        // TODO(corysmith): Validate the fraction type.
+        return true;
+      }
+    },
+    INTEGER(TAG_INTEGER) {
+      @Override
+      public boolean validate(String value) {
+        // TODO(corysmith): Validate the integer type.
+        return true;
+      }
+    },
+    ITEM(TAG_ITEM) {
+      @Override
+      public boolean validate(String value) {
+        // TODO(corysmith): Validate the item type.
+        return true;
+      }
+    },
+    LAYOUT(TAG_LAYOUT) {
+      @Override
+      public boolean validate(String value) {
+        // TODO(corysmith): Validate the layout type.
+        return true;
+      }
+    },
+    MENU(TAG_MENU) {
+      @Override
+      public boolean validate(String value) {
+        // TODO(corysmith): Validate the menu type.
+        return true;
+      }
+    },
+    MIPMAP(TAG_MIPMAP) {
+      @Override
+      public boolean validate(String value) {
+        // TODO(corysmith): Validate the mipmap type.
+        return true;
+      }
+    },
+    PUBLIC(TAG_PUBLIC) {
+      @Override
+      public boolean validate(String value) {
+        // TODO(corysmith): Validate the public type.
+        return true;
+      }
+    },
+    RAW(TAG_RAW) {
+      @Override
+      public boolean validate(String value) {
+        // TODO(corysmith): Validate the raw type.
+        return true;
+      }
+    },
+    STRING(TAG_STRING) {
+      @Override
+      public boolean validate(String value) {
+        return true;
+      }
+    };
     private final QName tagName;
 
     Type(QName tagName) {
       this.tagName = tagName;
     }
 
+    abstract boolean validate(String value);
+
     public static Type from(ResourceType resourceType) {
       for (Type valueType : values()) {
         if (valueType.tagName.getLocalPart().equals(resourceType.getName())) {
@@ -98,7 +177,8 @@
       throw new IllegalArgumentException(
           String.format(
               "%s resource type not found in available types: %s",
-              resourceType, Arrays.toString(values())));
+              resourceType,
+              Arrays.toString(values())));
     }
   }
 
@@ -120,7 +200,8 @@
     return of(Type.ITEM, ImmutableMap.of("type", resourceType.getName(), "format", format), value);
   }
 
-  public static XmlResourceValue itemWithValue(ResourceType resourceType, String value) {
+  public static XmlResourceValue itemWithValue(
+      ResourceType resourceType, String value) {
     return of(Type.ITEM, ImmutableMap.of("type", resourceType.getName()), value);
   }
 
@@ -184,11 +265,11 @@
             String.format(";%s,%d,%d", span.getTag(), span.getFirstChar(), span.getLastChar()));
       }
       stringValue = stringBuilder.toString();
-    } else if ((resourceType == ResourceType.COLOR || resourceType == ResourceType.DRAWABLE)
-        && item.hasPrim()) {
+    } else if ((resourceType == ResourceType.COLOR
+        || resourceType == ResourceType.DRAWABLE) && item.hasPrim()) {
       stringValue =
           String.format("#%1$8s", Integer.toHexString(item.getPrim().getData())).replace(' ', '0');
-    } else if (resourceType == ResourceType.INTEGER && item.hasPrim()) {
+    } else if (resourceType == ResourceType.INTEGER && item.hasPrim()){
       stringValue = Integer.toString(item.getPrim().getData());
     } else if (resourceType == ResourceType.BOOL && item.hasPrim()) {
       stringValue = item.getPrim().getData() == 0 ? "false" : "true";
@@ -201,7 +282,10 @@
           String.format("'%s' is not a valid resource type.", resourceType));
     }
 
-    return of(Type.valueOf(resourceType.toString().toUpperCase()), ImmutableMap.of(), stringValue);
+    return of(
+        Type.valueOf(resourceType.toString().toUpperCase()),
+        ImmutableMap.of(),
+        stringValue);
   }
 
   @Override
@@ -210,20 +294,23 @@
   }
 
   @Override
-  public void writeTo(OutputStream out) throws IOException {
-    final Builder builder =
-        DataValueXml.newBuilder()
-            .setType(XmlType.SIMPLE)
-            .setValueType(valueType.name())
+  public int serializeTo(int sourceId, Namespaces namespaces, OutputStream output)
+      throws IOException {
+    SerializeFormat.DataValue.Builder builder =
+        XmlResourceValues.newSerializableDataValueBuilder(sourceId);
+    Builder xmlValueBuilder =
+        builder
+            .getXmlValueBuilder()
+            .putAllNamespace(namespaces.asMap())
+            .setType(SerializeFormat.DataValueXml.XmlType.SIMPLE)
             // TODO(corysmith): Find a way to avoid writing strings to the serialized format
             // it's inefficient use of space and costs more when deserializing.
             .putAllAttribute(attributes);
-
     if (value != null) {
-      builder.setValue(value);
+      xmlValueBuilder.setValue(value);
     }
-
-    builder.build().writeDelimitedTo(out);
+    builder.setXmlValue(xmlValueBuilder.setValueType(valueType.name()));
+    return XmlResourceValues.serializeProtoDataValue(output, builder);
   }
 
   @Override
@@ -255,7 +342,7 @@
   public XmlResourceValue combineWith(XmlResourceValue value) {
     throw new IllegalArgumentException(this + " is not a combinable resource.");
   }
-
+  
   @Override
   public String asConflictStringWith(DataSource source) {
     if (value != null) {
diff --git a/src/tools/android/java/com/google/devtools/build/android/xml/StyleXmlResourceValue.java b/src/tools/android/java/com/google/devtools/build/android/xml/StyleXmlResourceValue.java
index 6929c9d..5cd0f6e 100644
--- a/src/tools/android/java/com/google/devtools/build/android/xml/StyleXmlResourceValue.java
+++ b/src/tools/android/java/com/google/devtools/build/android/xml/StyleXmlResourceValue.java
@@ -24,6 +24,7 @@
 import com.google.devtools.build.android.DataSource;
 import com.google.devtools.build.android.FullyQualifiedName;
 import com.google.devtools.build.android.XmlResourceValue;
+import com.google.devtools.build.android.XmlResourceValues;
 import com.google.devtools.build.android.proto.SerializeFormat;
 import com.google.devtools.build.android.proto.SerializeFormat.DataValueXml.XmlType;
 import java.io.IOException;
@@ -38,7 +39,8 @@
 /**
  * Represents an Android Style Resource.
  *
- * <p>Styles (http://developer.android.com/guide/topics/resources/style-resource.html) define a look
+ * <p>
+ * Styles (http://developer.android.com/guide/topics/resources/style-resource.html) define a look
  * and feel for a layout or other ui construct. They are effectively a s set of values that
  * correspond to &lt;attr&gt; resources defined either in the base android framework or in other
  * resources. They also allow inheritance on other styles. For a style to valid in a given resource
@@ -152,15 +154,19 @@
   }
 
   @Override
-  public void writeTo(OutputStream out) throws IOException {
+  public int serializeTo(int sourceId, Namespaces namespaces, OutputStream output)
+      throws IOException {
     SerializeFormat.DataValueXml.Builder xmlValueBuilder =
         SerializeFormat.DataValueXml.newBuilder()
             .setType(XmlType.STYLE)
+            .putAllNamespace(namespaces.asMap())
             .putAllMappedStringValue(values);
     if (parent != null) {
       xmlValueBuilder.setValue(parent);
     }
-    xmlValueBuilder.build().writeDelimitedTo(out);
+    return XmlResourceValues.serializeProtoDataValue(
+        output,
+        XmlResourceValues.newSerializableDataValueBuilder(sourceId).setXmlValue(xmlValueBuilder));
   }
 
   @Override
@@ -189,7 +195,7 @@
   public XmlResourceValue combineWith(XmlResourceValue value) {
     throw new IllegalArgumentException(this + " is not a combinable resource.");
   }
-
+  
   @Override
   public String asConflictStringWith(DataSource source) {
     return source.asConflictString();
diff --git a/src/tools/android/java/com/google/devtools/build/android/xml/StyleableXmlResourceValue.java b/src/tools/android/java/com/google/devtools/build/android/xml/StyleableXmlResourceValue.java
index 5006600..c966169 100644
--- a/src/tools/android/java/com/google/devtools/build/android/xml/StyleableXmlResourceValue.java
+++ b/src/tools/android/java/com/google/devtools/build/android/xml/StyleableXmlResourceValue.java
@@ -27,6 +27,7 @@
 import com.google.devtools.build.android.DataSource;
 import com.google.devtools.build.android.FullyQualifiedName;
 import com.google.devtools.build.android.XmlResourceValue;
+import com.google.devtools.build.android.XmlResourceValues;
 import com.google.devtools.build.android.proto.SerializeFormat;
 import com.google.devtools.build.android.proto.SerializeFormat.DataValueXml.XmlType;
 import java.io.IOException;
@@ -37,7 +38,6 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
-import java.util.stream.Collectors;
 import javax.annotation.concurrent.Immutable;
 
 /**
@@ -65,11 +65,22 @@
 
   static final Function<Entry<FullyQualifiedName, Boolean>, SerializeFormat.DataKey>
       FULLY_QUALIFIED_NAME_TO_DATA_KEY =
-          input -> input.getKey().toSerializedBuilder().setReference(input.getValue()).build();
+          new Function<Entry<FullyQualifiedName, Boolean>, SerializeFormat.DataKey>() {
+            @Override
+            public SerializeFormat.DataKey apply(Entry<FullyQualifiedName, Boolean> input) {
+              return input.getKey().toSerializedBuilder().setReference(input.getValue()).build();
+            }
+          };
 
   static final Function<SerializeFormat.DataKey, Entry<FullyQualifiedName, Boolean>>
       DATA_KEY_TO_FULLY_QUALIFIED_NAME =
-          input -> new SimpleEntry<>(FullyQualifiedName.fromProto(input), input.getReference());
+          new Function<SerializeFormat.DataKey, Entry<FullyQualifiedName, Boolean>>() {
+            @Override
+            public Entry<FullyQualifiedName, Boolean> apply(SerializeFormat.DataKey input) {
+              FullyQualifiedName key = FullyQualifiedName.fromProto(input);
+              return new SimpleEntry<FullyQualifiedName, Boolean>(key, input.getReference());
+            }
+          };
 
   private final ImmutableMap<FullyQualifiedName, Boolean> attrs;
 
@@ -134,17 +145,17 @@
   }
 
   @Override
-  public void writeTo(OutputStream out) throws IOException {
-    SerializeFormat.DataValueXml.newBuilder()
-        .setType(XmlType.STYLEABLE)
-        .addAllReferences(
-            attrs
-                .entrySet()
-                .stream()
-                .map(FULLY_QUALIFIED_NAME_TO_DATA_KEY)
-                .collect(Collectors.toSet()))
-        .build()
-        .writeDelimitedTo(out);
+  public int serializeTo(int sourceId, Namespaces namespaces, OutputStream output)
+      throws IOException {
+    return XmlResourceValues.serializeProtoDataValue(
+        output,
+        XmlResourceValues.newSerializableDataValueBuilder(sourceId)
+            .setXmlValue(
+                SerializeFormat.DataValueXml.newBuilder()
+                    .setType(XmlType.STYLEABLE)
+                    .putAllNamespace(namespaces.asMap())
+                    .addAllReferences(
+                        Iterables.transform(attrs.entrySet(), FULLY_QUALIFIED_NAME_TO_DATA_KEY))));
   }
 
   public static XmlResourceValue from(SerializeFormat.DataValueXml proto) {
@@ -191,12 +202,12 @@
   /**
    * Combines this instance with another {@link StyleableXmlResourceValue}.
    *
-   * <p>Defining two Styleables (undocumented in the official Android Docs) with the same {@link
-   * FullyQualifiedName} results in a single Styleable containing a union of all the attribute
-   * references.
+   * Defining two Styleables (undocumented in the official Android Docs) with the same
+   * {@link FullyQualifiedName} results in a single Styleable containing a union of all the
+   * attribute references.
    *
-   * @param value Another {@link StyleableXmlResourceValue} with the same {@link
-   *     FullyQualifiedName}.
+   * @param value Another {@link StyleableXmlResourceValue} with the same
+   *     {@link FullyQualifiedName}.
    * @return {@link StyleableXmlResourceValue} containing a sorted union of the attribute
    *     references.
    * @throws IllegalArgumentException if value is not an {@link StyleableXmlResourceValue}.