net.orfjackal.retrolambda.maven.ProcessClassesMojo Maven / Gradle / Ivy
// Copyright © 2013-2015 Esko Luontola
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0
package net.orfjackal.retrolambda.maven;
import com.google.common.base.*;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Files;
import net.orfjackal.retrolambda.*;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.*;
import org.apache.maven.plugins.annotations.*;
import org.apache.maven.project.MavenProject;
import org.apache.maven.toolchain.*;
import java.io.*;
import java.util.*;
import static org.twdata.maven.mojoexecutor.MojoExecutor.*;
abstract class ProcessClassesMojo extends AbstractMojo {
private static final Map targetBytecodeVersions = ImmutableMap.of(
"1.5", 49,
"1.6", 50,
"1.7", 51,
"1.8", 52
);
@Component
ToolchainManager toolchainManager;
@Component
private BuildPluginManager pluginManager;
@Parameter(defaultValue = "${session}", readonly = true)
private MavenSession session;
@Parameter(defaultValue = "${project}", readonly = true)
protected MavenProject project;
/**
* Directory of the Java 8 installation for running Retrolambda.
* The JRE to be used will be determined in priority order:
*
* - This parameter
* - JDK toolchain
* - Same as Maven
*
*
* @since 1.2.0
*/
@Parameter(property = "java8home", required = false)
public File java8home;
/**
* The Java version targeted by the bytecode processing. Possible values are
* 1.5, 1.6, 1.7 and 1.8. After processing the classes will be compatible
* with the target JVM provided the known limitations are considered. See
* project documentation
* for more details.
*
* @since 1.2.0
*/
@Parameter(defaultValue = "1.7", property = "retrolambdaTarget", required = true)
public String target;
/**
* Whether to backport default methods and static methods on interfaces.
* LIMITATIONS: All backported interfaces and all classes which implement
* them or call their static methods must be backported together,
* with one execution of Retrolambda.
*
* @since 2.0.0
*/
@Parameter(defaultValue = "false", property = "retrolambdaDefaultMethods", required = true)
public boolean defaultMethods;
/**
* Forces Retrolambda to run in a separate process. The default is not to fork,
* in which case Maven has to run under Java 8, or this plugin will fall back
* to forking. The forked process uses a Java agent hook for capturing the lambda
* classes generated by Java 8, whereas the non-forked version hooks into internal
* Java APIs, making it more susceptible to breaking between Java releases.
*
* @since 1.6.0
*/
@Parameter(defaultValue = "false")
public boolean fork;
protected abstract File getInputDir();
protected abstract File getOutputDir();
protected abstract List getClasspathElements() throws DependencyResolutionRequiredException;
@Override
public void execute() throws MojoExecutionException {
validateTarget();
validateFork();
if (fork) {
processClassesInForkedProcess();
} else {
processClassesInCurrentProcess();
}
}
private void validateTarget() throws MojoExecutionException {
if (!targetBytecodeVersions.containsKey(target)) {
String possibleValues = Joiner.on(", ").join(new TreeSet(targetBytecodeVersions.keySet()));
throw new MojoExecutionException(
"Unrecognized target '" + target + "'. Possible values are " + possibleValues);
}
}
private void validateFork() {
if (!fork && !Main.isRunningJava8()) {
getLog().warn("Maven is not running under Java 8 - forced to fork the process");
fork = true;
}
}
private void processClassesInCurrentProcess() throws MojoExecutionException {
getLog().info("Processing classes with Retrolambda");
try {
Properties p = new Properties();
p.setProperty(SystemPropertiesConfig.BYTECODE_VERSION, "" + targetBytecodeVersions.get(target));
p.setProperty(SystemPropertiesConfig.DEFAULT_METHODS, "" + defaultMethods);
p.setProperty(SystemPropertiesConfig.INPUT_DIR, getInputDir().getAbsolutePath());
p.setProperty(SystemPropertiesConfig.OUTPUT_DIR, getOutputDir().getAbsolutePath());
p.setProperty(SystemPropertiesConfig.CLASSPATH, getClasspath());
Retrolambda.run(new SystemPropertiesConfig(p));
} catch (Throwable t) {
throw new MojoExecutionException("Failed to run Retrolambda", t);
}
}
private void processClassesInForkedProcess() throws MojoExecutionException {
String version = getRetrolambdaVersion();
getLog().info("Retrieving Retrolambda " + version);
retrieveRetrolambdaJar(version);
getLog().info("Processing classes with Retrolambda");
String retrolambdaJar = getRetrolambdaJarPath();
File classpathFile = getClasspathFile();
try {
executeMojo(
plugin(groupId("org.apache.maven.plugins"),
artifactId("maven-antrun-plugin"),
version("1.7")),
goal("run"),
configuration(element(
"target",
element("exec",
attributes(
attribute("executable", getJavaCommand()),
attribute("failonerror", "true")),
element("arg", attribute("value", "-Dretrolambda.bytecodeVersion=" + targetBytecodeVersions.get(target))),
element("arg", attribute("value", "-Dretrolambda.defaultMethods=" + defaultMethods)),
element("arg", attribute("value", "-Dretrolambda.inputDir=" + getInputDir().getAbsolutePath())),
element("arg", attribute("value", "-Dretrolambda.outputDir=" + getOutputDir().getAbsolutePath())),
element("arg", attribute("value", "-Dretrolambda.classpathFile=" + classpathFile)),
element("arg", attribute("value", "-javaagent:" + retrolambdaJar)),
element("arg", attribute("value", "-jar")),
element("arg", attribute("value", retrolambdaJar))))),
executionEnvironment(project, session, pluginManager));
} finally {
if (!classpathFile.delete()) {
getLog().warn("Unable to delete " + classpathFile);
}
}
}
private void retrieveRetrolambdaJar(String version) throws MojoExecutionException {
// TODO: use Maven's built-in artifact resolving, so that we can refer to retrolambda.jar in the local repository without copying it
executeMojo(
plugin(groupId("org.apache.maven.plugins"),
artifactId("maven-dependency-plugin"),
version("2.8")),
goal("copy"),
configuration(element("artifactItems",
element("artifactItem",
element(name("groupId"), "net.orfjackal.retrolambda"),
element(name("artifactId"), "retrolambda"),
element(name("version"), version),
element(name("overWrite"), "true"),
element(name("outputDirectory"), getRetrolambdaJarDir()),
element(name("destFileName"), getRetrolambdaJarName())))),
executionEnvironment(project, session, pluginManager));
}
String getJavaCommand() {
String javaCommand = getJavaCommand(new File(System.getProperty("java.home")));
Toolchain tc = toolchainManager.getToolchainFromBuildContext("jdk", session);
if (tc != null) {
getLog().info("Toolchain in retrolambda-maven-plugin: " + tc);
javaCommand = tc.findTool("java");
}
if (java8home != null) {
if (tc != null) {
getLog().warn("Toolchains are ignored, 'java8home' parameter is set to " + java8home);
}
javaCommand = getJavaCommand(java8home);
}
return javaCommand;
}
private static String getJavaCommand(File javaHome) {
return new File(javaHome, "bin/java").getPath();
}
private String getClasspath() {
try {
return Joiner.on(File.pathSeparator).join(getClasspathElements());
} catch (DependencyResolutionRequiredException e) {
throw new RuntimeException(e);
}
}
private File getClasspathFile() {
try {
String classpath = Joiner.on("\n").join(getClasspathElements());
File file = File.createTempFile("retrolambda", "classpath");
file.deleteOnExit();
Files.write(classpath, file, Charsets.UTF_8);
return file;
} catch (DependencyResolutionRequiredException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private String getRetrolambdaJarPath() {
return getRetrolambdaJarDir() + "/" + getRetrolambdaJarName();
}
private String getRetrolambdaJarDir() {
return project.getBuild().getDirectory() + "/retrolambda";
}
private String getRetrolambdaJarName() {
return "retrolambda.jar";
}
private static String getRetrolambdaVersion() throws MojoExecutionException {
try {
InputStream is = ProcessClassesMojo.class.getResourceAsStream(
"/META-INF/maven/net.orfjackal.retrolambda/retrolambda-maven-plugin/pom.properties");
try {
Properties p = new Properties();
p.load(is);
return p.getProperty("version");
} finally {
is.close();
}
} catch (IOException e) {
throw new MojoExecutionException("Failed to detect the Retrolambda version", e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy