I'm trying to get the output of a Maven command in a static block - specifically - resolve the location of the local repository location to a static variable.
The application hangs only when the OutputHandler
is a lambda (not a method reference) and only when it's in a static initialiser (not just a static method).
Take the following minimised example:
pom.xml
:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.me</groupId>
<artifactId>maven-invoker-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-invoker</artifactId>
<version>3.2.0</version>
</dependency>
</dependencies>
</project>
InvokerTest.java
:
package maveninvokertest;
import java.io.File;
import java.util.Collections;
import org.apache.maven.shared.invoker.*;
public class InvokerTest {
static {
// doTest();
}
public static void main(final String[] args) {
doTest();
}
/**
* Run {@link #runMaven(InvocationOutputHandler)} against a method reference and lambda, both outputting to
* {@link System#out}
*/
private static void doTest() {
System.out.println("Method Reference:");
runMaven(System.out::println);
System.out.println("Lambda:");
runMaven(line -> System.out.println(line));
}
/** Run the {@code validate} command against Maven, outputting to {@code outputHandler} */
private static void runMaven(final InvocationOutputHandler outputHandler) {
try {
final InvocationRequest request = new DefaultInvocationRequest();
request.setMavenExecutable(new File("/opt/homebrew/bin/mvn"));
request.setGoals(Collections.singletonList("validate"));
request.setOutputHandler(outputHandler);
System.out.println(new DefaultInvoker().execute(request).getExitCode());
} catch (final Throwable t) {
t.printStackTrace();
}
}
}
This application runs some dummy goal, printing the output to the console and completing normally:
Method Reference:
[WARN] Maven will be executed in interactive mode, but no input stream has been configured for this MavenInvoker instance.
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------------< com.me:maventest >--------------------------
[INFO] Building maven-invoker-test 0.0.1-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.038 s
[INFO] Finished at: 2023-08-09T11:23:57+01:00
[INFO] ------------------------------------------------------------------------
0
Lambda:
[WARN] Maven will be executed in interactive mode, but no input stream has been configured for this MavenInvoker instance.
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------------< com.me:maventest >--------------------------
[INFO] Building maven-invoker-test 0.0.1-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.040 s
[INFO] Finished at: 2023-08-09T11:23:58+01:00
[INFO] ------------------------------------------------------------------------
0
Now lets move the doTest
call from the main
method into the static
initialiser block:
InvokerTest.java
:
package maveninvokertest;
import java.io.File;
import java.util.Collections;
import org.apache.maven.shared.invoker.*;
public class InvokerTest {
static {
doTest();
}
public static void main(final String[] args) {
// doTest();
}
/**
* Run {@link #runMaven(InvocationOutputHandler)} against a method reference and lambda, both outputting to
* {@link System#out}
*/
private static void doTest() {
System.out.println("Method Reference:");
runMaven(System.out::println);
System.out.println("Lambda:");
runMaven(line -> System.out.println(line));
}
/** Run the {@code validate} command against Maven, outputting to {@code outputHandler} */
private static void runMaven(final InvocationOutputHandler outputHandler) {
try {
final InvocationRequest request = new DefaultInvocationRequest();
request.setMavenExecutable(new File("/opt/homebrew/bin/mvn"));
request.setGoals(Collections.singletonList("validate"));
request.setOutputHandler(outputHandler);
System.out.println(new DefaultInvoker().execute(request).getExitCode());
} catch (final Throwable t) {
t.printStackTrace();
}
}
}
This should produce the same output, and yet instead...
Method Reference:
[WARN] Maven will be executed in interactive mode, but no input stream has been configured for this MavenInvoker instance.
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------------< com.me:maventest >--------------------------
[INFO] Building maventest 0.0.1-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.038 s
[INFO] Finished at: 2023-08-09T11:25:37+01:00
[INFO] ------------------------------------------------------------------------
0
Lambda:
[WARN] Maven will be executed in interactive mode, but no input stream has been configured for this MavenInvoker instance.
It gets this far and hangs.
Any ideas?