Overwrite duplicate srcjar entries
for bug-compatibility with JavaBuilder.
MOE_MIGRATED_REVID=137549121
diff --git a/java/com/google/turbine/main/Main.java b/java/com/google/turbine/main/Main.java
index 393a021..296afb6 100644
--- a/java/com/google/turbine/main/Main.java
+++ b/java/com/google/turbine/main/Main.java
@@ -42,6 +42,7 @@
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Enumeration;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@@ -101,6 +102,7 @@
Parser.parse(
new SourceFile(source, new String(Files.readAllBytes(Paths.get(source)), UTF_8))));
}
+ Map<String, SourceFile> sources = new LinkedHashMap<>();
for (String sourceJar : options.sourceJars()) {
try (JarFile jf = new JarFile(sourceJar)) {
Enumeration<JarEntry> entries = jf.entries();
@@ -113,14 +115,15 @@
// TODO(cushon): package-info.java files
continue;
}
- units.add(
- Parser.parse(
- new SourceFile(
- sourceJar + "!" + je.getName(),
- new String(ByteStreams.toByteArray(jf.getInputStream(je)), UTF_8))));
+ // overwrite existing entries for bug-compatibility with JavaBuilder (see b/26688023)
+ String source = new String(ByteStreams.toByteArray(jf.getInputStream(je)), UTF_8);
+ sources.put(je.getName(), new SourceFile(je.getName(), source));
}
}
}
+ for (SourceFile sourceFile : sources.values()) {
+ units.add(Parser.parse(sourceFile));
+ }
return units.build();
}
diff --git a/javatests/com/google/turbine/main/MainTest.java b/javatests/com/google/turbine/main/MainTest.java
new file mode 100644
index 0000000..85597ae
--- /dev/null
+++ b/javatests/com/google/turbine/main/MainTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2016 Google Inc. 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.turbine.main;
+
+import static com.google.common.truth.Truth.assertThat;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.io.ByteStreams;
+import com.google.turbine.options.TurbineOptions;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Opcodes;
+
+@RunWith(JUnit4.class)
+public class MainTest {
+
+ static final ImmutableList<String> BOOTCLASSPATH =
+ ImmutableList.of(Paths.get(System.getProperty("java.home")).resolve("lib/rt.jar").toString());
+
+ @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Test
+ public void sourceJarClash() throws IOException {
+ Path sourcesa = temporaryFolder.newFile("sourcesa.jar").toPath();
+ try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(sourcesa))) {
+ jos.putNextEntry(new JarEntry("Test.java"));
+ jos.write("class Test { public static final String CONST = \"ONE\"; }".getBytes(UTF_8));
+ }
+ Path sourcesb = temporaryFolder.newFile("sourcesb.jar").toPath();
+ try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(sourcesb))) {
+ jos.putNextEntry(new JarEntry("Test.java"));
+ jos.write("class Test { public static final String CONST = \"TWO\"; }".getBytes(UTF_8));
+ }
+ Path output = temporaryFolder.newFile("output.jar").toPath();
+
+ boolean ok =
+ Main.compile(
+ TurbineOptions.builder()
+ .setSourceJars(ImmutableList.of(sourcesa.toString(), sourcesb.toString()))
+ .addBootClassPathEntries(BOOTCLASSPATH)
+ .setOutput(output.toString())
+ .setTempDir("")
+ .build());
+ assertThat(ok).isTrue();
+
+ Map<String, byte[]> data = readJar(output);
+ Map<String, Object> fields = new LinkedHashMap<>();
+ new ClassReader(data.get("Test.class"))
+ .accept(
+ new ClassVisitor(Opcodes.ASM5) {
+ @Override
+ public FieldVisitor visitField(
+ int access, String name, String desc, String signature, Object value) {
+ fields.put(name, value);
+ return null;
+ }
+ },
+ 0);
+ assertThat(fields).containsEntry("CONST", "TWO");
+ }
+
+ private Map<String, byte[]> readJar(Path output) throws IOException {
+ Map<String, byte[]> data = new LinkedHashMap<>();
+ try (JarFile jf = new JarFile(output.toFile())) {
+ Enumeration<JarEntry> entries = jf.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry je = entries.nextElement();
+ data.put(je.getName(), ByteStreams.toByteArray(jf.getInputStream(je)));
+ }
+ }
+ return data;
+ }
+}