Skip to content

Allow processing of jars #129

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
3 changes: 1 addition & 2 deletions end-to-end-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>net.orfjackal.retrolambda</groupId>
<artifactId>parent</artifactId>
<version>2.5.8-SNAPSHOT</version>
<version>2.6.0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>

Expand Down Expand Up @@ -54,7 +54,6 @@
<scope>system</scope>
<systemPath>${basedir}/src/test/lib/java-lang-dummies.jar</systemPath>
</dependency>

</dependencies>

<build>
Expand Down
2 changes: 1 addition & 1 deletion parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

<groupId>net.orfjackal.retrolambda</groupId>
<artifactId>parent</artifactId>
<version>2.5.8-SNAPSHOT</version>
<version>2.6.0-SNAPSHOT</version>
<packaging>pom</packaging>

<description>Backport of Java 8 lambda expressions to Java 7</description>
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>net.orfjackal.retrolambda</groupId>
<artifactId>parent</artifactId>
<version>2.5.8-SNAPSHOT</version>
<version>2.6.0-SNAPSHOT</version>
<relativePath>parent/pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion retrolambda-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>net.orfjackal.retrolambda</groupId>
<artifactId>parent</artifactId>
<version>2.5.8-SNAPSHOT</version>
<version>2.6.0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
2 changes: 1 addition & 1 deletion retrolambda-maven-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>net.orfjackal.retrolambda</groupId>
<artifactId>parent</artifactId>
<version>2.5.8-SNAPSHOT</version>
<version>2.6.0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion retrolambda/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>net.orfjackal.retrolambda</groupId>
<artifactId>parent</artifactId>
<version>2.5.8-SNAPSHOT</version>
<version>2.6.0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public interface Config {

List<Path> getIncludedFiles();

List<Path> getJars();

boolean isJavacHacksEnabled();

boolean isQuiet();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.*;
Expand Down Expand Up @@ -32,6 +33,7 @@ public static void run(Config config) throws Throwable {
Path outputDir = config.getOutputDir();
List<Path> classpath = config.getClasspath();
List<Path> includedFiles = config.getIncludedFiles();
List<Path> jars = config.getJars();
boolean isJavacHacksEnabled = config.isJavacHacksEnabled();
if (config.isQuiet()) {
Log.WARN();
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -102,10 +105,18 @@ protected void visitResource(Path relativePath, byte[] content) throws IOExcepti
}
}

static void visitFiles(Path inputDir, List<Path> includedFiles, FileVisitor<Path> visitor) throws IOException {
static void visitFiles(Path inputDir, List<Path> includedFiles, List<Path> jars, FileVisitor<Path> 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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,31 @@ public List<Path> 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<Path> 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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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));
}
Expand All @@ -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<Path> includedFiles = Arrays.asList(file1, fileInSubdir);

Retrolambda.visitFiles(inputDir, includedFiles, visitor);
Retrolambda.visitFiles(inputDir, includedFiles, null, visitor);

assertThat(visitedFiles, containsInAnyOrder(file1, fileInSubdir));
}
Expand All @@ -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<Path> 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<Path> jars = Arrays.asList(jar);

Retrolambda.visitFiles(inputDir, null, jars, visitor);
List<URI> 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"))));
}
}