diff --git a/.gitignore b/.gitignore
index 56256e4e..43d35826 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
/target/
/*/target/
+.classpath
+.settings
+.project
diff --git a/README.md b/README.md
index fedc8e43..c90104a7 100644
--- a/README.md
+++ b/README.md
@@ -66,16 +66,33 @@ Optional system properties:
Output directory into where the generated class files are written.
Defaults to same as retrolambda.inputDir
```
+### Maven plugin
+To run Retrolambda using Maven add the following to your pom.xml:
+```xml
+
+
+ ...
+
+ net.orfjackal.retrolambda
+ retrolambda-maven-plugin
+ 0.1.15-SNAPSHOT
+
+
+
+ process-main
+ process-test
+
+
+
+
+ ...
+```
+See [end-to-end-tests/pom.xml](https://github.com/orfjackal/retrolambda/blob/master/end-to-end-tests/pom.xml) for an example.
+Plugin documentation is [here](). (TODO decide where to put the site report)
### Tips
-For an example of how to run Retrolambda using Maven, see how
-maven-dependency-plugin and maven-antrun-plugin are used in
-[end-to-end-tests/pom.xml](https://github.com/orfjackal/retrolambda/blob/master/end-to-end-tests/pom.xml)
-There isn't yet a Maven plugin for doing that with less boilerplate, but maybe
-later.
-
During development, inside an IDE, it's the easiest to use Java 8, without
Retrolamba, to compile and run tests. But in your continuous integration build
you should run tests using the target Java version. For example, you can
diff --git a/end-to-end-tests/pom.xml b/end-to-end-tests/pom.xml
index 8c90f19c..41f0c47a 100644
--- a/end-to-end-tests/pom.xml
+++ b/end-to-end-tests/pom.xml
@@ -47,7 +47,24 @@
+
+ net.orfjackal.retrolambda
+ retrolambda-maven-plugin
+ ${project.parent.version}
+
+
+
+ process-main
+ process-test
+
+
+
+
+
+
+
+
diff --git a/parent/pom.xml b/parent/pom.xml
index e2815777..1c2cbf3f 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -283,12 +283,12 @@
maven-plugin-plugin
- 3.1
+ 3.2
maven-site-plugin
- 3.1
+ 3.3
diff --git a/pom.xml b/pom.xml
index eec3a15c..8ba38404 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,6 +18,7 @@
parent
retrolambda
+ retrolambda-maven-plugin
end-to-end-tests
diff --git a/retrolambda-maven-plugin/pom.xml b/retrolambda-maven-plugin/pom.xml
new file mode 100644
index 00000000..f946ffe9
--- /dev/null
+++ b/retrolambda-maven-plugin/pom.xml
@@ -0,0 +1,153 @@
+
+ 4.0.0
+
+ net.orfjackal.retrolambda
+ parent
+ 1.1.5-SNAPSHOT
+ ../parent/pom.xml
+
+ retrolambda-maven-plugin
+ maven-plugin
+
+ ${project.artifactId}
+
+ https://github.com/orfjackal/retrolambda
+
+
+ UTF-8
+
+
+
+ ${minimumMavenVersion}
+
+
+
+
+ org.apache.maven
+ maven-plugin-api
+ 2.0
+
+
+ org.apache.maven.plugin-tools
+ maven-plugin-annotations
+ 3.2
+ provided
+
+
+ org.codehaus.plexus
+ plexus-utils
+ 3.0.8
+
+
+ org.twdata.maven
+ mojo-executor
+ 2.2.0
+
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ true
+ true
+ 1.6
+ 1.6
+
+
+
+ org.apache.maven.plugins
+ maven-plugin-plugin
+
+ retrolambda
+ true
+
+
+
+ mojo-descriptor
+
+ descriptor
+
+ process-classes
+
+
+ help-goal
+
+ helpmojo
+
+ process-classes
+
+
+
+
+ org.apache.maven.plugins
+ maven-site-plugin
+
+
+ attach-descriptor
+
+ attach-descriptor
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-plugin-plugin
+ 3.2
+
+
+
+
+
+
+
+
+ run-its
+
+
+
+ org.apache.maven.plugins
+ maven-invoker-plugin
+ 1.7
+
+ true
+ ${project.build.directory}/it
+
+ */pom.xml
+
+ verify
+ ${project.build.directory}/local-repo
+ src/it/settings.xml
+
+ clean
+ test-compile
+
+
+
+
+ integration-test
+
+ install
+ integration-test
+ verify
+
+
+
+
+
+
+
+
+
diff --git a/retrolambda-maven-plugin/src/it/settings.xml b/retrolambda-maven-plugin/src/it/settings.xml
new file mode 100644
index 00000000..c8f77f0b
--- /dev/null
+++ b/retrolambda-maven-plugin/src/it/settings.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+ it-repo
+
+ true
+
+
+
+ local.central
+ @localRepositoryUrl@
+
+ true
+
+
+ true
+
+
+
+
+
+ local.central
+ @localRepositoryUrl@
+
+ true
+
+
+ true
+
+
+
+
+
+
diff --git a/retrolambda-maven-plugin/src/it/simple-it/pom.xml b/retrolambda-maven-plugin/src/it/simple-it/pom.xml
new file mode 100644
index 00000000..a229afc7
--- /dev/null
+++ b/retrolambda-maven-plugin/src/it/simple-it/pom.xml
@@ -0,0 +1,34 @@
+
+
+ 4.0.0
+
+ net.orfjackal.retrolambda.it
+ simple-it
+ 1.0-SNAPSHOT
+
+ A simple IT verifying the basic use case.
+
+
+ UTF-8
+
+
+
+
+
+ @project.groupId@
+ @project.artifactId@
+ @project.version@
+
+
+ touch
+ validate
+
+ touch
+
+
+
+
+
+
+
diff --git a/retrolambda-maven-plugin/src/it/simple-it/verify.groovy b/retrolambda-maven-plugin/src/it/simple-it/verify.groovy
new file mode 100644
index 00000000..7b307c78
--- /dev/null
+++ b/retrolambda-maven-plugin/src/it/simple-it/verify.groovy
@@ -0,0 +1,3 @@
+File touchFile = new File( basedir, "target/touch.txt" );
+
+assert touchFile.isFile()
diff --git a/retrolambda-maven-plugin/src/main/java/net/orfjackal/retrolambda/maven/ClassesType.java b/retrolambda-maven-plugin/src/main/java/net/orfjackal/retrolambda/maven/ClassesType.java
new file mode 100644
index 00000000..478048c0
--- /dev/null
+++ b/retrolambda-maven-plugin/src/main/java/net/orfjackal/retrolambda/maven/ClassesType.java
@@ -0,0 +1,5 @@
+package net.orfjackal.retrolambda.maven;
+
+enum ClassesType {
+ MAIN, TEST;
+}
diff --git a/retrolambda-maven-plugin/src/main/java/net/orfjackal/retrolambda/maven/ProcessClassesMojo.java b/retrolambda-maven-plugin/src/main/java/net/orfjackal/retrolambda/maven/ProcessClassesMojo.java
new file mode 100644
index 00000000..7fbb3287
--- /dev/null
+++ b/retrolambda-maven-plugin/src/main/java/net/orfjackal/retrolambda/maven/ProcessClassesMojo.java
@@ -0,0 +1,206 @@
+package net.orfjackal.retrolambda.maven;
+
+import static org.twdata.maven.mojoexecutor.MojoExecutor.artifactId;
+import static org.twdata.maven.mojoexecutor.MojoExecutor.attribute;
+import static org.twdata.maven.mojoexecutor.MojoExecutor.attributes;
+import static org.twdata.maven.mojoexecutor.MojoExecutor.configuration;
+import static org.twdata.maven.mojoexecutor.MojoExecutor.element;
+import static org.twdata.maven.mojoexecutor.MojoExecutor.executeMojo;
+import static org.twdata.maven.mojoexecutor.MojoExecutor.executionEnvironment;
+import static org.twdata.maven.mojoexecutor.MojoExecutor.goal;
+import static org.twdata.maven.mojoexecutor.MojoExecutor.groupId;
+import static org.twdata.maven.mojoexecutor.MojoExecutor.name;
+import static org.twdata.maven.mojoexecutor.MojoExecutor.plugin;
+import static org.twdata.maven.mojoexecutor.MojoExecutor.version;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.BuildPluginManager;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+
+abstract class ProcessClassesMojo extends AbstractMojo {
+
+ private static final String VERSION_DEPENDENCY = "2.0";
+ private static final String GROUP_ID_DEPENDENCY = "org.apache.maven.plugins";
+ private static final String ARTIFACT_ID_DEPENDENCY = "maven-dependency-plugin";
+ private static final String VERSION_ANTRUN = "1.7";
+
+ private static final String GROUP_ID_ANTRUN = "org.apache.maven.plugins";
+ private static final String ARTIFACT_ID_ANTRUN = "maven-antrun-plugin";
+
+ private static final String RETROLAMBDA_JAR = "retrolambda.jar";
+
+ private final Map targetBytecodeVersions = new HashMap();
+
+ @Component
+ private MavenSession session;
+
+ @Component
+ private BuildPluginManager pluginManager;
+
+ @Component
+ private MavenProject project;
+
+ /**
+ * The location of the java 8 jdk (not jre).
+ */
+ @Parameter(required = false, property = "java8home", defaultValue = "${env.JAVA8_HOME}")
+ private String 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.
+ */
+ @Parameter(required = false, property = "retrolambdaTarget", defaultValue = "1.7")
+ private String target;
+
+ /**
+ * The directory containing the main (non-test) compiled classes. These
+ * classes will be overwritten with bytecode changes to obtain compatibility
+ * with target java runtime.
+ */
+ @Parameter(required = false, property = "retrolambdaMainClassesDir", defaultValue = "${project.build.outputDirectory}")
+ private String mainClassesDir;
+
+ /**
+ * The directory containing the compiled test classes. These classes will be
+ * overwritten with bytecode changes to obtain compatibility with target
+ * java runtime.
+ */
+ @Parameter(required = false, property = "retrolambdaTestClassesDir", defaultValue = "${project.build.testOutputDirectory}")
+ private String testClassesDir;
+
+ private final ClassesType classesType;
+
+ /**
+ * Constructor.
+ *
+ * @param classesType
+ */
+ ProcessClassesMojo(ClassesType classesType) {
+ this.classesType = classesType;
+ targetBytecodeVersions.put("1.5", 49);
+ targetBytecodeVersions.put("1.6", 50);
+ targetBytecodeVersions.put("1.7", 51);
+ targetBytecodeVersions.put("1.8", 52);
+ }
+
+ @Override
+ public void execute() throws MojoExecutionException {
+ Log log = getLog();
+ log.info("starting execution");
+ validateJava8home();
+ validateTarget();
+ String retrolambdaVersion = getRetrolambdaVersion();
+ executeMojo(
+ plugin(groupId(GROUP_ID_DEPENDENCY),
+ artifactId(ARTIFACT_ID_DEPENDENCY),
+ version(VERSION_DEPENDENCY)),
+ goal("copy"),
+ configuration(element(
+ "artifactItems",
+ element("artifactItem",
+ element(name("groupId"),
+ "net.orfjackal.retrolambda"),
+ element(name("artifactId"), "retrolambda"),
+ element(name("version"), retrolambdaVersion),
+ element(name("overWrite"), "true"),
+ element(name("outputDirectory"), project
+ .getBuild().getDirectory()),
+ element(name("destFileName"), RETROLAMBDA_JAR)))),
+ executionEnvironment(project, session, pluginManager));
+ log.info("copied retrolambda.jar to build directory");
+ log.info("processing classes");
+ if (classesType == ClassesType.MAIN)
+ processClasses(mainClassesDir, "maven.compile.classpath");
+ else
+ processClasses(testClassesDir, "maven.test.classpath");
+ log.info("processed classes");
+ }
+
+ private void validateTarget() throws MojoExecutionException {
+ if (!targetBytecodeVersions.containsKey(target))
+ throw new MojoExecutionException(
+ "unrecognized target '"
+ + target
+ + "'. Possible values are 1.5, 1.6 ,1.7 ,1.8 representing those versions of java.");
+ }
+
+ private void validateJava8home() throws MojoExecutionException {
+ File jdk = new File(java8home);
+ if (!jdk.exists() || !jdk.isDirectory()) {
+ throw new MojoExecutionException(
+ "must set configuration element java8home or environment variable JAVA8_HOME to a valid jdk 8 location");
+ }
+ }
+
+ private void processClasses(String input, String classpathId)
+ throws MojoExecutionException {
+
+ executeMojo(
+ plugin(groupId(GROUP_ID_ANTRUN),
+ artifactId(ARTIFACT_ID_ANTRUN), version(VERSION_ANTRUN)),
+ goal("run"),
+ configuration(element(
+ "target",
+ element("property",
+ attributes(attribute("name", "the_classpath"),
+ attribute("refid", classpathId))),
+ element("exec",
+ attributes(
+ attribute("executable", java8home
+ + "/bin/java"),
+ attribute("failonerror", "true")),
+ element("arg",
+ attribute(
+ "value",
+ "-Dretrolambda.bytecodeVersion="
+ + targetBytecodeVersions
+ .get(target))),
+ element("arg",
+ attribute("value",
+ "-Dretrolambda.inputDir="
+ + input)),
+ element("arg",
+ attribute("value",
+ "-Dretrolambda.classpath=${the_classpath}")),
+ element("arg",
+ attribute("value", "-javaagent:"
+ + project.getBuild()
+ .getDirectory() + "/"
+ + RETROLAMBDA_JAR)),
+ element("arg", attribute("value", "-jar")),
+ element("arg",
+ attribute("value", project.getBuild()
+ .getDirectory()
+ + "/"
+ + RETROLAMBDA_JAR))))),
+ executionEnvironment(project, session, pluginManager));
+ }
+
+ private static String getRetrolambdaVersion() {
+ InputStream is = ProcessClassesMojo.class
+ .getResourceAsStream("/retrolambda.properties");
+ Properties p = new Properties();
+ try {
+ p.load(is);
+ return p.getProperty("retrolambda.version");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/retrolambda-maven-plugin/src/main/java/net/orfjackal/retrolambda/maven/ProcessMainClassesMojo.java b/retrolambda-maven-plugin/src/main/java/net/orfjackal/retrolambda/maven/ProcessMainClassesMojo.java
new file mode 100644
index 00000000..2e01f1d1
--- /dev/null
+++ b/retrolambda-maven-plugin/src/main/java/net/orfjackal/retrolambda/maven/ProcessMainClassesMojo.java
@@ -0,0 +1,17 @@
+package net.orfjackal.retrolambda.maven;
+
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+
+/**
+ * Processes main (non-test) classes compiled with java 8 so that they are
+ * compatible with java 5,6 or 7 runtime.
+ */
+@Mojo(name = "process-main", defaultPhase = LifecyclePhase.PROCESS_CLASSES)
+public class ProcessMainClassesMojo extends ProcessClassesMojo {
+
+ public ProcessMainClassesMojo() {
+ super(ClassesType.MAIN);
+ }
+
+}
diff --git a/retrolambda-maven-plugin/src/main/java/net/orfjackal/retrolambda/maven/ProcessTestClassesMojo.java b/retrolambda-maven-plugin/src/main/java/net/orfjackal/retrolambda/maven/ProcessTestClassesMojo.java
new file mode 100644
index 00000000..85a0d8d2
--- /dev/null
+++ b/retrolambda-maven-plugin/src/main/java/net/orfjackal/retrolambda/maven/ProcessTestClassesMojo.java
@@ -0,0 +1,16 @@
+package net.orfjackal.retrolambda.maven;
+
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+
+/**
+ * Processes test classes compiled with java 8 so that they are compatible with
+ * java 5,6 or 7 runtime.
+ */
+@Mojo(name = "process-test", defaultPhase = LifecyclePhase.PROCESS_TEST_CLASSES)
+public class ProcessTestClassesMojo extends ProcessClassesMojo {
+
+ public ProcessTestClassesMojo() {
+ super(ClassesType.TEST);
+ }
+}
\ No newline at end of file
diff --git a/retrolambda-maven-plugin/src/main/resources/retrolambda.properties b/retrolambda-maven-plugin/src/main/resources/retrolambda.properties
new file mode 100644
index 00000000..23f123d4
--- /dev/null
+++ b/retrolambda-maven-plugin/src/main/resources/retrolambda.properties
@@ -0,0 +1 @@
+retrolambda.version=${project.version}
\ No newline at end of file