aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/android/java/com/google/devtools/build/android/resources
diff options
context:
space:
mode:
authorGravatar corysmith <corysmith@google.com>2017-05-22 18:40:35 +0200
committerGravatar Irina Iancu <elenairina@google.com>2017-05-23 12:46:00 +0200
commit7cc7ae4a018936e08982fb58fd749dfada37f82e (patch)
tree256c6f29154a61c1992c8887e4d2c11f8aa0a18b /src/tools/android/java/com/google/devtools/build/android/resources
parentf1c23532d1f05b731f28d2c474ec146e2332606e (diff)
Move the field name out of the FieldInitializer
RELNOTES: None PiperOrigin-RevId: 156747534
Diffstat (limited to 'src/tools/android/java/com/google/devtools/build/android/resources')
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializer.java16
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializers.java71
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/resources/IntArrayFieldInitializer.java62
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/resources/IntFieldInitializer.java57
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java54
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/resources/RSourceGenerator.java10
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java50
7 files changed, 145 insertions, 175 deletions
diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializer.java b/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializer.java
index edcc464c18..ff7e9b875e 100644
--- a/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializer.java
+++ b/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializer.java
@@ -15,7 +15,6 @@ package com.google.devtools.build.android.resources;
import java.io.IOException;
import java.io.Writer;
-import java.util.Collection;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.commons.InstructionAdapter;
@@ -23,27 +22,20 @@ import org.objectweb.asm.commons.InstructionAdapter;
* Represents a field and its initializer (where initialization is either part of the field
* definition, or done via code in the static clinit function).
*/
-public interface FieldInitializer extends Comparable<FieldInitializer> {
+public interface FieldInitializer {
/**
* Write the bytecode for the field definition.
*
* @return true if the initializer is deferred to clinit code.
*/
- boolean writeFieldDefinition(ClassWriter cw, int accessLevel, boolean isFinal);
+ boolean writeFieldDefinition(String fieldName, ClassWriter cw, int accessLevel, boolean isFinal);
/**
* Write the bytecode for the clinit portion of initializer.
- *
* @return the number of stack slots needed for the code.
*/
- int writeCLInit(InstructionAdapter insts, String className);
+ int writeCLInit(String fieldName, InstructionAdapter insts, String className);
/** Write the source code for the initializer to the given writer. */
- void writeInitSource(Writer writer, boolean finalFields) throws IOException;
-
- /** Tests if the field's name is in the provided collection. */
- boolean nameIsIn(Collection<String> fieldNames);
-
- /** Adds fieldName to the provided set. */
- void addTo(Collection<String> fieldNames);
+ void writeInitSource(String fieldName, Writer writer, boolean finalFields) throws IOException;
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializers.java b/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializers.java
index 45ffadf66d..ae8307ed90 100644
--- a/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializers.java
+++ b/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializers.java
@@ -16,65 +16,78 @@ package com.google.devtools.build.android.resources;
import com.android.resources.ResourceType;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.MultimapBuilder;
-import com.google.common.collect.SortedSetMultimap;
+import com.google.common.collect.ImmutableSortedMap;
+import com.google.common.collect.Sets;
import java.util.Collection;
+import java.util.EnumMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.SortedSet;
+import java.util.TreeMap;
/**
* Represents a collection of resource symbols and values suitable for writing java sources and
* classes.
*/
public class FieldInitializers
- implements Iterable<Entry<ResourceType, Collection<FieldInitializer>>> {
+ implements Iterable<Entry<ResourceType, Map<String, FieldInitializer>>> {
- private final Map<ResourceType, Collection<FieldInitializer>> initializers;
+ private final Map<ResourceType, Map<String, FieldInitializer>> initializers;
- private FieldInitializers(Map<ResourceType, Collection<FieldInitializer>> initializers) {
+ private FieldInitializers(Map<ResourceType, Map<String, FieldInitializer>> initializers) {
this.initializers = initializers;
}
/** Creates a {@link FieldInitializers} copying the contents from a {@link Map}. */
public static FieldInitializers copyOf(
- Map<ResourceType, Collection<FieldInitializer>> initializers) {
+ Map<ResourceType, Map<String, FieldInitializer>> initializers) {
return new FieldInitializers(ImmutableMap.copyOf(initializers));
}
- public Iterable<Entry<ResourceType, Collection<FieldInitializer>>> filter(
- FieldInitializers fieldsToWrite) {
- final SortedSetMultimap<ResourceType, FieldInitializer> initializersToWrite =
- MultimapBuilder.enumKeys(ResourceType.class).treeSetValues().build();
-
- // Create a map to filter with.
- final SortedSetMultimap<ResourceType, String> symbolsToWrite =
- MultimapBuilder.enumKeys(ResourceType.class).treeSetValues().build();
- for (Entry<ResourceType, Collection<FieldInitializer>> entry :
- fieldsToWrite.initializers.entrySet()) {
- for (FieldInitializer initializer : entry.getValue()) {
- final SortedSet<String> fieldNames = symbolsToWrite.get(entry.getKey());
- initializer.addTo(fieldNames);
+ public static FieldInitializers mergedFrom(Collection<FieldInitializers> toMerge) {
+ final Map<ResourceType, Map<String, FieldInitializer>> merged =
+ new EnumMap<>(ResourceType.class);
+ for (FieldInitializers mergee : toMerge) {
+ for (Entry<ResourceType, Map<String, FieldInitializer>> entry : mergee) {
+ final Map<String, FieldInitializer> fieldMap =
+ merged.containsKey(entry.getKey())
+ ? merged.get(entry.getKey())
+ : new TreeMap<String, FieldInitializer>();
+ merged.put(entry.getKey(), fieldMap);
+ for (Entry<String, FieldInitializer> field : entry.getValue().entrySet()) {
+ fieldMap.put(field.getKey(), field.getValue());
+ }
}
}
+ return copyOf(merged);
+ }
- for (Entry<ResourceType, Collection<String>> entry : symbolsToWrite.asMap().entrySet()) {
- // Resource type may be missing if resource overriding eliminates resources at the binary
- // level, which were originally present at the library level.
+ public Iterable<Entry<ResourceType, Map<String, FieldInitializer>>> filter(
+ FieldInitializers fieldsToWrite) {
+ Map<ResourceType, Map<String, FieldInitializer>> initializersToWrite =
+ new EnumMap<>(ResourceType.class);
+
+ for (Entry<ResourceType, Map<String, FieldInitializer>> entry :
+ fieldsToWrite.initializers.entrySet()) {
if (initializers.containsKey(entry.getKey())) {
- for (FieldInitializer field : initializers.get(entry.getKey())) {
- if (field.nameIsIn(entry.getValue())) {
- initializersToWrite.put(entry.getKey(), field);
- }
+ final Map<String, FieldInitializer> valueFields = initializers.get(entry.getKey());
+ final ImmutableMap.Builder<String, FieldInitializer> fields =
+ ImmutableSortedMap.naturalOrder();
+ // Resource type may be missing if resource overriding eliminates resources at the binary
+ // level, which were originally present at the library level.
+ for (String fieldName :
+ Sets.intersection(entry.getValue().keySet(), valueFields.keySet())) {
+ fields.put(fieldName, valueFields.get(fieldName));
}
+ initializersToWrite.put(entry.getKey(), fields.build());
}
}
- return initializersToWrite.asMap().entrySet();
+
+ return initializersToWrite.entrySet();
}
@Override
- public Iterator<Entry<ResourceType, Collection<FieldInitializer>>> iterator() {
+ public Iterator<Entry<ResourceType, Map<String, FieldInitializer>>> iterator() {
return initializers.entrySet().iterator();
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/IntArrayFieldInitializer.java b/src/tools/android/java/com/google/devtools/build/android/resources/IntArrayFieldInitializer.java
index 2f595c90f5..140439cd5b 100644
--- a/src/tools/android/java/com/google/devtools/build/android/resources/IntArrayFieldInitializer.java
+++ b/src/tools/android/java/com/google/devtools/build/android/resources/IntArrayFieldInitializer.java
@@ -20,53 +20,50 @@ import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.io.Writer;
-import java.util.Collection;
import java.util.Objects;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
-/**
- * Models an int[] field initializer.
- */
+/** Models an int[] field initializer. */
public final class IntArrayFieldInitializer implements FieldInitializer {
public static final String DESC = "[I";
- private final String fieldName;
private final ImmutableCollection<Integer> values;
- public IntArrayFieldInitializer(String fieldName, ImmutableCollection<Integer> values) {
- this.fieldName = fieldName;
+ private IntArrayFieldInitializer(ImmutableCollection<Integer> values) {
this.values = values;
}
- public static FieldInitializer of(String name, String value) {
+ public static FieldInitializer of(String value) {
Preconditions.checkArgument(value.startsWith("{ "), "Expected list starting with { ");
Preconditions.checkArgument(value.endsWith(" }"), "Expected list ending with } ");
// Check for an empty list, which is "{ }".
if (value.length() < 4) {
- return new IntArrayFieldInitializer(name, ImmutableList.<Integer>of());
+ return of(ImmutableList.<Integer>of());
}
ImmutableList.Builder<Integer> intValues = ImmutableList.builder();
String trimmedValue = value.substring(2, value.length() - 2);
- Iterable<String> valueStrings = Splitter.on(',')
- .trimResults()
- .split(trimmedValue);
+ Iterable<String> valueStrings = Splitter.on(',').trimResults().split(trimmedValue);
for (String valueString : valueStrings) {
intValues.add(Integer.decode(valueString));
}
- return new IntArrayFieldInitializer(name, intValues.build());
+ return of(intValues.build());
+ }
+
+ public static IntArrayFieldInitializer of(ImmutableCollection<Integer> values) {
+ return new IntArrayFieldInitializer(values);
}
@Override
- public boolean writeFieldDefinition(ClassWriter cw, int accessLevel, boolean isFinal) {
- cw.visitField(accessLevel, fieldName, DESC, null, null)
- .visitEnd();
+ public boolean writeFieldDefinition(
+ String fieldName, ClassWriter cw, int accessLevel, boolean isFinal) {
+ cw.visitField(accessLevel, fieldName, DESC, null, null).visitEnd();
return true;
}
@Override
- public int writeCLInit(InstructionAdapter insts, String className) {
+ public int writeCLInit(String fieldName, InstructionAdapter insts, String className) {
insts.iconst(values.size());
insts.newarray(Type.INT_TYPE);
int curIndex = 0;
@@ -84,7 +81,8 @@ public final class IntArrayFieldInitializer implements FieldInitializer {
}
@Override
- public void writeInitSource(Writer writer, boolean finalFields) throws IOException {
+ public void writeInitSource(String fieldName, Writer writer, boolean finalFields)
+ throws IOException {
StringBuilder builder = new StringBuilder();
boolean first = true;
for (Integer attrId : values) {
@@ -103,43 +101,21 @@ public final class IntArrayFieldInitializer implements FieldInitializer {
}
@Override
- public boolean nameIsIn(Collection<String> fieldNames) {
- return fieldNames.contains(fieldName);
- }
-
- @Override
public String toString() {
- return MoreObjects.toStringHelper(getClass())
- .add("fieldName", fieldName)
- .add("values", values)
- .toString();
- }
-
- @Override
- public int compareTo(FieldInitializer other) {
- if (other instanceof IntArrayFieldInitializer) {
- return fieldName.compareTo(((IntArrayFieldInitializer) other).fieldName);
- }
- // IntArrays will go after IntFields
- return 1;
+ return MoreObjects.toStringHelper(getClass()).add("values", values).toString();
}
@Override
public int hashCode() {
- return Objects.hash(fieldName, values);
+ return values.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof IntArrayFieldInitializer) {
IntArrayFieldInitializer other = (IntArrayFieldInitializer) obj;
- return Objects.equals(fieldName, other.fieldName) && Objects.equals(values, other.values);
+ return Objects.equals(values, other.values);
}
return false;
}
-
- @Override
- public void addTo(Collection<String> fieldNames) {
- fieldNames.add(fieldName);
- }
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/IntFieldInitializer.java b/src/tools/android/java/com/google/devtools/build/android/resources/IntFieldInitializer.java
index ffbd64fcda..888e888f0b 100644
--- a/src/tools/android/java/com/google/devtools/build/android/resources/IntFieldInitializer.java
+++ b/src/tools/android/java/com/google/devtools/build/android/resources/IntFieldInitializer.java
@@ -16,38 +16,36 @@ package com.google.devtools.build.android.resources;
import com.google.common.base.MoreObjects;
import java.io.IOException;
import java.io.Writer;
-import java.util.Collection;
-import java.util.Objects;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.commons.InstructionAdapter;
-/**
- * Models an int field initializer.
- */
+/** Models an int field initializer. */
public final class IntFieldInitializer implements FieldInitializer {
- private final String fieldName;
private final int value;
private static final String DESC = "I";
- public IntFieldInitializer(String fieldName, int value) {
- this.fieldName = fieldName;
+ private IntFieldInitializer(int value) {
this.value = value;
}
- public static FieldInitializer of(String name, String value) {
- return new IntFieldInitializer(name, Integer.decode(value));
+ public static FieldInitializer of(String value) {
+ return of(Integer.decode(value));
+ }
+
+ public static IntFieldInitializer of(int value) {
+ return new IntFieldInitializer(value);
}
@Override
- public boolean writeFieldDefinition(ClassWriter cw, int accessLevel, boolean isFinal) {
- cw.visitField(accessLevel, fieldName, DESC, null, isFinal ? value : null)
- .visitEnd();
+ public boolean writeFieldDefinition(
+ String fieldName, ClassWriter cw, int accessLevel, boolean isFinal) {
+ cw.visitField(accessLevel, fieldName, DESC, null, isFinal ? value : null).visitEnd();
return !isFinal;
}
@Override
- public int writeCLInit(InstructionAdapter insts, String className) {
+ public int writeCLInit(String fieldName, InstructionAdapter insts, String className) {
insts.iconst(value);
insts.putstatic(className, fieldName, DESC);
// Just needs one stack slot for the iconst.
@@ -55,7 +53,8 @@ public final class IntFieldInitializer implements FieldInitializer {
}
@Override
- public void writeInitSource(Writer writer, boolean finalFields) throws IOException {
+ public void writeInitSource(String fieldName, Writer writer, boolean finalFields)
+ throws IOException {
writer.write(
String.format(
" public static %sint %s = 0x%x;\n",
@@ -63,43 +62,21 @@ public final class IntFieldInitializer implements FieldInitializer {
}
@Override
- public boolean nameIsIn(Collection<String> fieldNames) {
- return fieldNames.contains(fieldName);
- }
-
- @Override
public String toString() {
- return MoreObjects.toStringHelper(getClass())
- .add("fieldName", fieldName)
- .add("value", value)
- .toString();
- }
-
- @Override
- public int compareTo(FieldInitializer other) {
- if (other instanceof IntFieldInitializer) {
- return fieldName.compareTo(((IntFieldInitializer) other).fieldName);
- }
- // IntFields will go before Intarrays
- return -1;
+ return MoreObjects.toStringHelper(getClass()).add("value", value).toString();
}
@Override
public int hashCode() {
- return Objects.hash(fieldName, value);
+ return value;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof IntFieldInitializer) {
IntFieldInitializer other = (IntFieldInitializer) obj;
- return Objects.equals(fieldName, other.fieldName) && value == other.value;
+ return value == other.value;
}
return false;
}
-
- @Override
- public void addTo(Collection<String> fieldNames) {
- fieldNames.add(fieldName);
- }
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java b/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java
index 54375fab14..ea09b5bbd3 100644
--- a/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java
+++ b/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java
@@ -20,9 +20,7 @@ import com.google.common.collect.Iterables;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.objectweb.asm.ClassWriter;
@@ -46,18 +44,6 @@ public class RClassGenerator {
private static final Splitter PACKAGE_SPLITTER = Splitter.on('.');
/**
- * Create an RClassGenerator initialized with the ResourceSymbols values.
- *
- * @param outFolder base folder to place the output R class files.
- * @param values the final symbol values
- * @param finalFields true if the fields should be marked final
- */
- public static RClassGenerator fromSymbols(
- Path outFolder, ResourceSymbols values, boolean finalFields) {
- return with(outFolder, values.asInitializers(), finalFields);
- }
-
- /**
* Create an RClassGenerator given a collection of initializers.
*
* @param outFolder base folder to place the output R class files.
@@ -82,17 +68,17 @@ public class RClassGenerator {
public void write(String packageName, FieldInitializers symbolsToWrite) throws IOException {
writeClasses(packageName, initializers.filter(symbolsToWrite));
}
-
+
/** Builds bytecode and writes out R.class file, and R$inner.class files for provided package. */
public void write(String packageName) throws IOException {
writeClasses(packageName, initializers);
}
-
+
private void writeClasses(
String packageName,
- Iterable<Entry<ResourceType, Collection<FieldInitializer>>> initializersToWrite)
+ Iterable<Entry<ResourceType, Map<String, FieldInitializer>>> initializersToWrite)
throws IOException {
-
+
Iterable<String> folders = PACKAGE_SPLITTER.split(packageName);
Path packageDir = outFolder;
for (String folder : folders) {
@@ -101,11 +87,11 @@ public class RClassGenerator {
// At least create the outFolder that was requested. However, if there are no symbols, don't
// create the R.class and inner class files (no need to have an empty class).
Files.createDirectories(packageDir);
-
+
if (Iterables.isEmpty(initializersToWrite)) {
return;
}
-
+
Path rClassFile = packageDir.resolve(SdkConstants.FN_COMPILED_RESOURCE_CLASS);
String packageWithSlashes = packageName.replaceAll("\\.", "/");
@@ -121,7 +107,7 @@ public class RClassGenerator {
classWriter.visitSource(SdkConstants.FN_RESOURCE_CLASS, null);
writeConstructor(classWriter);
// Build the R.class w/ the inner classes, then later build the individual R$inner.class.
- for (Entry<ResourceType, Collection<FieldInitializer>> entry : initializersToWrite) {
+ for (Entry<ResourceType, Map<String, FieldInitializer>> entry : initializersToWrite) {
String innerClassName = rClassName + "$" + entry.getKey().toString();
classWriter.visitInnerClass(
innerClassName,
@@ -132,13 +118,13 @@ public class RClassGenerator {
classWriter.visitEnd();
Files.write(rClassFile, classWriter.toByteArray());
// Now generate the R$inner.class files.
- for (Map.Entry<ResourceType, Collection<FieldInitializer>> entry : initializersToWrite) {
+ for (Map.Entry<ResourceType, Map<String, FieldInitializer>> entry : initializersToWrite) {
writeInnerClass(entry.getValue(), packageDir, rClassName, entry.getKey().toString());
}
}
private void writeInnerClass(
- Collection<FieldInitializer> initializers,
+ Map<String, FieldInitializer> initializers,
Path packageDir,
String fullyQualifiedOuterClass,
String innerClass)
@@ -147,14 +133,16 @@ public class RClassGenerator {
String fullyQualifiedInnerClass =
writeInnerClassHeader(fullyQualifiedOuterClass, innerClass, innerClassWriter);
- List<FieldInitializer> deferredInitializers = new ArrayList<>();
+ Map<String, FieldInitializer> deferredInitializers = new LinkedHashMap<>();
int fieldAccessLevel = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC;
if (finalFields) {
fieldAccessLevel |= Opcodes.ACC_FINAL;
}
- for (FieldInitializer init : initializers) {
- if (init.writeFieldDefinition(innerClassWriter, fieldAccessLevel, finalFields)) {
- deferredInitializers.add(init);
+ for (Entry<String, FieldInitializer> entry : initializers.entrySet()) {
+ FieldInitializer init = entry.getValue();
+ if (init.writeFieldDefinition(
+ entry.getKey(), innerClassWriter, fieldAccessLevel, finalFields)) {
+ deferredInitializers.put(entry.getKey(), init);
}
}
if (!deferredInitializers.isEmpty()) {
@@ -199,15 +187,19 @@ public class RClassGenerator {
}
private static void writeStaticClassInit(
- ClassWriter classWriter, String className, List<FieldInitializer> initializers) {
+ ClassWriter classWriter,
+ String className,
+ Map<String, FieldInitializer> deferredInitializers) {
MethodVisitor visitor =
classWriter.visitMethod(
Opcodes.ACC_STATIC, "<clinit>", "()V", null, /* signature */ null /* exceptions */);
visitor.visitCode();
int stackSlotsNeeded = 0;
InstructionAdapter insts = new InstructionAdapter(visitor);
- for (FieldInitializer fieldInit : initializers) {
- stackSlotsNeeded = Math.max(stackSlotsNeeded, fieldInit.writeCLInit(insts, className));
+ for (Entry<String, FieldInitializer> fieldEntry : deferredInitializers.entrySet()) {
+ final FieldInitializer fieldInit = fieldEntry.getValue();
+ stackSlotsNeeded =
+ Math.max(stackSlotsNeeded, fieldInit.writeCLInit(fieldEntry.getKey(), insts, className));
}
insts.areturn(Type.VOID_TYPE);
visitor.visitMaxs(stackSlotsNeeded, 0);
diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/RSourceGenerator.java b/src/tools/android/java/com/google/devtools/build/android/resources/RSourceGenerator.java
index 4c3ef8581f..ffaab026d0 100644
--- a/src/tools/android/java/com/google/devtools/build/android/resources/RSourceGenerator.java
+++ b/src/tools/android/java/com/google/devtools/build/android/resources/RSourceGenerator.java
@@ -22,7 +22,7 @@ import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.Collection;
+import java.util.Map;
import java.util.Map.Entry;
/** Writes out an R.java source. */
@@ -62,7 +62,7 @@ public class RSourceGenerator {
private void writeSource(
String packageName,
- Iterable<Entry<ResourceType, Collection<FieldInitializer>>> initializersToWrite)
+ Iterable<Entry<ResourceType, Map<String, FieldInitializer>>> initializersToWrite)
throws IOException {
String packageDir = packageName.replace('.', '/');
Path packagePath = outputBasePath.resolve(packageDir);
@@ -82,11 +82,11 @@ public class RSourceGenerator {
writer.write(" */\n");
writer.write(String.format("package %s;\n", packageName));
writer.write("public final class R {\n");
- for (Entry<ResourceType, Collection<FieldInitializer>> entry : initializersToWrite) {
+ for (Entry<ResourceType, Map<String, FieldInitializer>> entry : initializersToWrite) {
writer.write(
String.format(" public static final class %s {\n", entry.getKey().getName()));
- for (FieldInitializer field : entry.getValue()) {
- field.writeInitSource(writer, finalFields);
+ for (Entry<String, FieldInitializer> fieldEntry : entry.getValue().entrySet()) {
+ fieldEntry.getValue().writeInitSource(fieldEntry.getKey(), writer, finalFields);
}
writer.write(" }\n");
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java b/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java
index 6b2dbcff7b..b98dfefa64 100644
--- a/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java
+++ b/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java
@@ -18,8 +18,6 @@ import com.android.builder.dependency.SymbolFileProvider;
import com.android.resources.ResourceType;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
-import com.google.common.collect.MultimapBuilder;
-import com.google.common.collect.SortedSetMultimap;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import java.io.File;
@@ -27,12 +25,15 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.TreeMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.logging.Logger;
@@ -55,8 +56,8 @@ public class ResourceSymbols {
public ResourceSymbols call() throws Exception {
List<String> lines = Files.readAllLines(rTxtSymbols, StandardCharsets.UTF_8);
- final SortedSetMultimap<ResourceType, FieldInitializer> initializers =
- MultimapBuilder.enumKeys(ResourceType.class).treeSetValues().build();
+ Map<ResourceType, Map<String, FieldInitializer>> initializers =
+ new EnumMap<>(ResourceType.class);
for (int lineIndex = 1; lineIndex <= lines.size(); lineIndex++) {
String line = null;
@@ -74,10 +75,17 @@ public class ResourceSymbols {
String value = line.substring(pos3 + 1);
final ResourceType resourceType = ResourceType.getEnum(className);
+ final Map<String, FieldInitializer> fields;
+ if (initializers.containsKey(resourceType)) {
+ fields = initializers.get(resourceType);
+ } else {
+ fields = new TreeMap<>();
+ initializers.put(resourceType, fields);
+ }
if ("int".equals(type)) {
- initializers.put(resourceType, IntFieldInitializer.of(name, value));
+ fields.put(name, IntFieldInitializer.of(value));
} else {
- initializers.put(resourceType, IntArrayFieldInitializer.of(name, value));
+ fields.put(name, IntArrayFieldInitializer.of(value));
}
} catch (IndexOutOfBoundsException e) {
String s =
@@ -88,7 +96,7 @@ public class ResourceSymbols {
throw new IOException(s, e);
}
}
- return ResourceSymbols.from(FieldInitializers.copyOf(initializers.asMap()));
+ return ResourceSymbols.from(FieldInitializers.copyOf(initializers));
}
}
@@ -141,15 +149,11 @@ public class ResourceSymbols {
}
public static ResourceSymbols merge(Collection<ResourceSymbols> symbolTables) {
- final SortedSetMultimap<ResourceType, FieldInitializer> initializers =
- MultimapBuilder.enumKeys(ResourceType.class).treeSetValues().build();
+ List<FieldInitializers> fieldInitializers = new ArrayList<>(symbolTables.size());
for (ResourceSymbols symbolTableProvider : symbolTables) {
- for (Entry<ResourceType, Collection<FieldInitializer>> entry :
- symbolTableProvider.asInitializers()) {
- initializers.putAll(entry.getKey(), entry.getValue());
- }
+ fieldInitializers.add(symbolTableProvider.asInitializers());
}
- return from(FieldInitializers.copyOf(initializers.asMap()));
+ return from(FieldInitializers.mergedFrom(fieldInitializers));
}
/** Read the symbols from the provided symbol file. */
@@ -173,7 +177,7 @@ public class ResourceSymbols {
* @param finalFields
* @throws IOException when encountering an error during writing.
*/
- public void writeTo(
+ public void writeSourcesTo(
Path sourceOut,
String packageName,
Collection<ResourceSymbols> packageSymbols,
@@ -187,4 +191,20 @@ public class ResourceSymbols {
return values;
}
+ public void writeClassesTo(
+ Multimap<String, ResourceSymbols> libMap,
+ String appPackageName,
+ Path classesOut,
+ boolean finalFields)
+ throws IOException {
+ RClassGenerator classWriter = RClassGenerator.with(classesOut, values, finalFields);
+ for (String packageName : libMap.keySet()) {
+ classWriter.write(packageName, ResourceSymbols.merge(libMap.get(packageName)).values);
+ }
+ if (appPackageName != null) {
+ // Unlike the R.java generation, we also write the app's R.class file so that the class
+ // jar file can be complete (aapt doesn't generate it for us).
+ classWriter.write(appPackageName);
+ }
+ }
}