diff --git a/README.md b/README.md
index e2ff38e7..6adff942 100644
--- a/README.md
+++ b/README.md
@@ -140,6 +140,16 @@ Configurable system properties:
Alternative to retrolambda.includedFiles for avoiding the command line
length limit. The file must list one file per line with UTF-8 encoding.
+ retrolambda.jars
+ List of jars to process.
+ This is useful for including libraries.
+ Uses ; or : as the path separator, see java.io.File#pathSeparatorChar
+
+ retrolambda.jarsFile (alternative)
+ File listing the jars to process.
+ Alternative to retrolambda.jars for avoiding the command line
+ length limit. The file must list one file per line with UTF-8 encoding.
+
retrolambda.javacHacks
Attempts to fix javac bugs (type-annotation emission for local variables).
Disabled by default. Enable by setting to "true"
diff --git a/end-to-end-tests/pom.xml b/end-to-end-tests/pom.xml
index 1cdf9652..751f512d 100644
--- a/end-to-end-tests/pom.xml
+++ b/end-to-end-tests/pom.xml
@@ -6,7 +6,7 @@
net.orfjackal.retrolambda
parent
- 2.5.8-SNAPSHOT
+ 2.6.0-SNAPSHOT
../parent/pom.xml
@@ -54,7 +54,6 @@
system
${basedir}/src/test/lib/java-lang-dummies.jar
-
diff --git a/parent/pom.xml b/parent/pom.xml
index 9e43dc49..6aaac0ba 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -12,7 +12,7 @@
net.orfjackal.retrolambda
parent
- 2.5.8-SNAPSHOT
+ 2.6.0-SNAPSHOT
pom
Backport of Java 8 lambda expressions to Java 7
diff --git a/pom.xml b/pom.xml
index e8265b5f..e5f4b900 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
net.orfjackal.retrolambda
parent
- 2.5.8-SNAPSHOT
+ 2.6.0-SNAPSHOT
parent/pom.xml
diff --git a/retrolambda-api/pom.xml b/retrolambda-api/pom.xml
index d82d4b7d..9e517e66 100644
--- a/retrolambda-api/pom.xml
+++ b/retrolambda-api/pom.xml
@@ -6,7 +6,7 @@
net.orfjackal.retrolambda
parent
- 2.5.8-SNAPSHOT
+ 2.6.0-SNAPSHOT
../parent/pom.xml
diff --git a/retrolambda-api/src/main/java/net/orfjackal/retrolambda/api/RetrolambdaApi.java b/retrolambda-api/src/main/java/net/orfjackal/retrolambda/api/RetrolambdaApi.java
index 7276b978..8a0203e3 100644
--- a/retrolambda-api/src/main/java/net/orfjackal/retrolambda/api/RetrolambdaApi.java
+++ b/retrolambda-api/src/main/java/net/orfjackal/retrolambda/api/RetrolambdaApi.java
@@ -12,6 +12,8 @@ public class RetrolambdaApi {
public static final String INCLUDED_FILES_FILE = INCLUDED_FILES + "File";
public static final String CLASSPATH = PREFIX + "classpath";
public static final String CLASSPATH_FILE = CLASSPATH + "File";
+ public static final String JARS = "jars";
+ public static final String JARS_FILE = JARS + "File";
public static final String OUTPUT_DIR = PREFIX + "outputDir";
public static final String INPUT_DIR = PREFIX + "inputDir";
public static final String DEFAULT_METHODS = PREFIX + "defaultMethods";
diff --git a/retrolambda-maven-plugin/pom.xml b/retrolambda-maven-plugin/pom.xml
index 951a593c..3fd1ae1f 100644
--- a/retrolambda-maven-plugin/pom.xml
+++ b/retrolambda-maven-plugin/pom.xml
@@ -5,7 +5,7 @@
net.orfjackal.retrolambda
parent
- 2.5.8-SNAPSHOT
+ 2.6.0-SNAPSHOT
../parent/pom.xml
diff --git a/retrolambda/pom.xml b/retrolambda/pom.xml
index bd0df18e..70fda115 100644
--- a/retrolambda/pom.xml
+++ b/retrolambda/pom.xml
@@ -6,7 +6,7 @@
net.orfjackal.retrolambda
parent
- 2.5.8-SNAPSHOT
+ 2.6.0-SNAPSHOT
../parent/pom.xml
diff --git a/retrolambda/src/main/java/net/orfjackal/retrolambda/Config.java b/retrolambda/src/main/java/net/orfjackal/retrolambda/Config.java
index e5d2c983..8ba20865 100644
--- a/retrolambda/src/main/java/net/orfjackal/retrolambda/Config.java
+++ b/retrolambda/src/main/java/net/orfjackal/retrolambda/Config.java
@@ -21,6 +21,8 @@ public interface Config {
List getIncludedFiles();
+ List getJars();
+
boolean isJavacHacksEnabled();
boolean isQuiet();
diff --git a/retrolambda/src/main/java/net/orfjackal/retrolambda/Retrolambda.java b/retrolambda/src/main/java/net/orfjackal/retrolambda/Retrolambda.java
index 07d292f0..0453910a 100644
--- a/retrolambda/src/main/java/net/orfjackal/retrolambda/Retrolambda.java
+++ b/retrolambda/src/main/java/net/orfjackal/retrolambda/Retrolambda.java
@@ -5,6 +5,7 @@
package net.orfjackal.retrolambda;
import com.esotericsoftware.minlog.Log;
+import com.google.common.collect.ImmutableMap;
import net.orfjackal.retrolambda.files.*;
import net.orfjackal.retrolambda.interfaces.ClassInfo;
import net.orfjackal.retrolambda.lambdas.*;
@@ -32,6 +33,7 @@ public static void run(Config config) throws Throwable {
Path outputDir = config.getOutputDir();
List classpath = config.getClasspath();
List includedFiles = config.getIncludedFiles();
+ List jars = config.getJars();
boolean isJavacHacksEnabled = config.isJavacHacksEnabled();
if (config.isQuiet()) {
Log.WARN();
@@ -44,6 +46,7 @@ public static void run(Config config) throws Throwable {
Log.info("Output directory: " + outputDir);
Log.info("Classpath: " + classpath);
Log.info("Included files: " + (includedFiles != null ? includedFiles.size() : "all"));
+ Log.info("Jars: " + (jars != null ? jars.size() : 0));
Log.info("JVM version: " + System.getProperty("java.version"));
Log.info("Agent enabled: " + Agent.isEnabled());
Log.info("javac hacks: " + isJavacHacksEnabled);
@@ -67,7 +70,7 @@ public static void run(Config config) throws Throwable {
dumper.install();
}
- visitFiles(inputDir, includedFiles, new ClasspathVisitor() {
+ visitFiles(inputDir, includedFiles, jars, new ClasspathVisitor() {
@Override
protected void visitClass(byte[] bytecode) {
analyzer.analyze(bytecode, isJavacHacksEnabled);
@@ -102,10 +105,18 @@ protected void visitResource(Path relativePath, byte[] content) throws IOExcepti
}
}
- static void visitFiles(Path inputDir, List includedFiles, FileVisitor visitor) throws IOException {
+ static void visitFiles(Path inputDir, List includedFiles, List jars, FileVisitor visitor) throws IOException {
if (includedFiles != null) {
visitor = new FilteringFileVisitor(includedFiles, visitor);
}
+ if (jars != null) {
+ for (Path jar : jars) {
+ URI uri = URI.create("jar:file:" + jar.toUri().getPath());
+ try (FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap())) {
+ Files.walkFileTree(fileSystem.getPath("/"), visitor);
+ }
+ }
+ }
Files.walkFileTree(inputDir, visitor);
}
diff --git a/retrolambda/src/main/java/net/orfjackal/retrolambda/SystemPropertiesConfig.java b/retrolambda/src/main/java/net/orfjackal/retrolambda/SystemPropertiesConfig.java
index 18afb719..05529cbe 100644
--- a/retrolambda/src/main/java/net/orfjackal/retrolambda/SystemPropertiesConfig.java
+++ b/retrolambda/src/main/java/net/orfjackal/retrolambda/SystemPropertiesConfig.java
@@ -190,6 +190,31 @@ public List getIncludedFiles() {
return null;
}
+ // jars
+
+ static {
+ optionalParameterHelp(JARS,
+ "List of jars to process.",
+ "This is useful for including libraries.",
+ "Uses ; or : as the path separator, see java.io.File#pathSeparatorChar");
+ alternativeParameterHelp(JARS_FILE, JARS,
+ "File listing the files to process, instead of processing all files.",
+ "Alternative to " + JARS + " for avoiding the command line",
+ "length limit. The file must list one file per line with UTF-8 encoding.");
+ }
+
+ @Override
+ public List getJars() {
+ String files = p.getProperty(JARS);
+ if (files != null) {
+ return parsePathList(files);
+ }
+ String filesFile = p.getProperty(JARS_FILE);
+ if (filesFile != null) {
+ return readPathList(Paths.get(filesFile));
+ }
+ return null;
+ }
// useJavac8ReadLabelHack
diff --git a/retrolambda/src/main/java/net/orfjackal/retrolambda/files/ClasspathVisitor.java b/retrolambda/src/main/java/net/orfjackal/retrolambda/files/ClasspathVisitor.java
index 72dfad58..56088839 100644
--- a/retrolambda/src/main/java/net/orfjackal/retrolambda/files/ClasspathVisitor.java
+++ b/retrolambda/src/main/java/net/orfjackal/retrolambda/files/ClasspathVisitor.java
@@ -22,7 +22,7 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
- Path relativePath = baseDir.relativize(file);
+ Path relativePath = safeRelativize(baseDir, file);
byte[] content = Files.readAllBytes(file);
if (isJavaClass(relativePath)) {
@@ -33,6 +33,18 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
return FileVisitResult.CONTINUE;
}
+ /**
+ * The path might point into a jar which will throw an IllegalArgumentException. In that case, just return a path
+ * relative to the root of the jar.
+ */
+ private static Path safeRelativize(Path baseDir, Path file) {
+ try {
+ return baseDir.relativize(file);
+ } catch (IllegalArgumentException e) {
+ return file.subpath(1, file.getNameCount());
+ }
+ }
+
protected abstract void visitClass(byte[] bytecode) throws IOException;
protected abstract void visitResource(Path relativePath, byte[] content) throws IOException;
diff --git a/retrolambda/src/main/java/net/orfjackal/retrolambda/files/OutputDirectory.java b/retrolambda/src/main/java/net/orfjackal/retrolambda/files/OutputDirectory.java
index 085effa1..a5e9e3e8 100644
--- a/retrolambda/src/main/java/net/orfjackal/retrolambda/files/OutputDirectory.java
+++ b/retrolambda/src/main/java/net/orfjackal/retrolambda/files/OutputDirectory.java
@@ -28,7 +28,7 @@ public void writeClass(byte[] bytecode, boolean isJavacHacksEnabled) throws IOEx
}
public void writeFile(Path relativePath, byte[] content) throws IOException {
- Path outputFile = outputDir.resolve(relativePath);
+ Path outputFile = outputDir.resolve(relativePath.toString());
Files.createDirectories(outputFile.getParent());
Files.write(outputFile, content);
}
diff --git a/retrolambda/src/test/java/net/orfjackal/retrolambda/RetrolambdaTest.java b/retrolambda/src/test/java/net/orfjackal/retrolambda/RetrolambdaTest.java
index 8e74d823..2051d375 100644
--- a/retrolambda/src/test/java/net/orfjackal/retrolambda/RetrolambdaTest.java
+++ b/retrolambda/src/test/java/net/orfjackal/retrolambda/RetrolambdaTest.java
@@ -4,14 +4,18 @@
package net.orfjackal.retrolambda;
+import com.google.common.collect.ImmutableMap;
import net.orfjackal.retrolambda.api.RetrolambdaApi;
import org.junit.*;
import org.junit.rules.TemporaryFolder;
-import java.io.IOException;
+import java.io.*;
+import java.net.URI;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
+import java.util.jar.*;
+import java.util.stream.Collectors;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
@@ -37,6 +41,8 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
private Path file2;
private Path fileInSubdir;
private Path outsider;
+ private Path jar;
+ private Path fileInJar;
@Before
public void setup() throws IOException {
@@ -48,11 +54,15 @@ public void setup() throws IOException {
Files.createDirectory(subdir);
fileInSubdir = Files.createFile(subdir.resolve("file.txt"));
outsider = tempDir.newFile("outsider.txt").toPath();
+ jar = new File(tempDir.getRoot(), "file.jar").toPath();
+ try (FileSystem jarFileSystem = FileSystems.newFileSystem(URI.create("jar:file:" + jar.toUri().getPath()), ImmutableMap.of("create", "true"))) {
+ fileInJar = Files.createFile(jarFileSystem.getPath("/").resolve("file.txt"));
+ }
}
@Test
public void by_default_visits_all_files_recursively() throws IOException {
- Retrolambda.visitFiles(inputDir, null, visitor);
+ Retrolambda.visitFiles(inputDir, null, null, visitor);
assertThat(visitedFiles, containsInAnyOrder(file1, file2, fileInSubdir));
}
@@ -61,7 +71,7 @@ public void by_default_visits_all_files_recursively() throws IOException {
public void when_included_files_is_set_then_visits_only_those_files() throws IOException {
List includedFiles = Arrays.asList(file1, fileInSubdir);
- Retrolambda.visitFiles(inputDir, includedFiles, visitor);
+ Retrolambda.visitFiles(inputDir, includedFiles, null, visitor);
assertThat(visitedFiles, containsInAnyOrder(file1, fileInSubdir));
}
@@ -70,11 +80,21 @@ public void when_included_files_is_set_then_visits_only_those_files() throws IOE
public void ignores_included_files_that_are_outside_the_input_directory() throws IOException {
List includedFiles = Arrays.asList(file1, outsider);
- Retrolambda.visitFiles(inputDir, includedFiles, visitor);
+ Retrolambda.visitFiles(inputDir, includedFiles, null, visitor);
assertThat(visitedFiles, containsInAnyOrder(file1));
}
+ @Test
+ public void visits_files_in_jar() throws IOException {
+ List jars = Arrays.asList(jar);
+
+ Retrolambda.visitFiles(inputDir, null, jars, visitor);
+ List uris = visitedFiles.stream().map(Path::toUri).collect(Collectors.toList());
+
+ assertThat(uris, containsInAnyOrder(file1.toUri(), file2.toUri(), fileInSubdir.toUri(), fileInJar.toUri()));
+ }
+
@Test
public void copies_resources_to_output_directory() throws Throwable {
Properties p = new Properties();
diff --git a/retrolambda/src/test/java/net/orfjackal/retrolambda/SystemPropertiesConfigTest.java b/retrolambda/src/test/java/net/orfjackal/retrolambda/SystemPropertiesConfigTest.java
index 1c9a403e..d3b5735b 100644
--- a/retrolambda/src/test/java/net/orfjackal/retrolambda/SystemPropertiesConfigTest.java
+++ b/retrolambda/src/test/java/net/orfjackal/retrolambda/SystemPropertiesConfigTest.java
@@ -149,4 +149,36 @@ public void included_files_file() throws IOException {
systemProperties.setProperty(RetrolambdaApi.INCLUDED_FILES_FILE, file.toString());
assertThat("multiple values", config().getIncludedFiles(), is(Arrays.asList(Paths.get("one.class"), Paths.get("two.class"))));
}
+
+ @Test
+ public void jars() throws IOException {
+ assertThat("not set", config().getJars(), is(nullValue()));
+
+ systemProperties.setProperty(SystemPropertiesConfig.JARS, "");
+ assertThat("zero values", config().getJars(), is(empty()));
+
+ systemProperties.setProperty(SystemPropertiesConfig.JARS, "/foo/one.jar");
+ assertThat("one value", config().getJars(), is(Arrays.asList(Paths.get("/foo/one.jar"))));
+
+ systemProperties.setProperty(SystemPropertiesConfig.JARS, "/foo/one.jar" + File.pathSeparator + "/foo/two.jar");
+ assertThat("multiple values", config().getJars(), is(Arrays.asList(Paths.get("/foo/one.jar"), Paths.get("/foo/two.jar"))));
+ }
+
+ @Test
+ public void jars_file() throws IOException {
+ Path file = tempDir.newFile("jars.txt").toPath();
+ assertThat("not set", config().getJars(), is(nullValue()));
+
+ Files.write(file, Arrays.asList("", "", "")); // empty lines are ignored
+ systemProperties.setProperty(SystemPropertiesConfig.JARS_FILE, file.toString());
+ assertThat("zero values", config().getJars(), is(empty()));
+
+ Files.write(file, Arrays.asList("one.jar"));
+ systemProperties.setProperty(SystemPropertiesConfig.JARS_FILE, file.toString());
+ assertThat("one value", config().getJars(), is(Arrays.asList(Paths.get("one.jar"))));
+
+ Files.write(file, Arrays.asList("one.jar", "two.jar"));
+ systemProperties.setProperty(SystemPropertiesConfig.JARS_FILE, file.toString());
+ assertThat("multiple values", config().getJars(), is(Arrays.asList(Paths.get("one.jar"), Paths.get("two.jar"))));
+ }
}