.jpg

One Small Step for Maven

The fabulous JCrete unconference ends with a “hack day”. I never thought I could contribute anything useful in a few hours, but this year Maurice Naftalin and myself succeeded. Version 3.6.0 of the exec-maven-plugin contains the fruit of our labor. Now you can use Maven to execute an “instance main method”.

JEP 512

This is one of my favorite features of Java 25. You can now write a “Hello, World” program as follows:

void main() {
    System.out.println("Hello, World!);
}

You can actually do a bit better, and use IO.println, but that’s unrelated to this topic, so I won’t dwell on it.

No class declaration. When you place the code in a file HelloWorld.java, a class HelloWorld is automatically inferred. That’s the “compact source files” feature of JEP 512, and it is also tangential to the exec-maven-plugin. The maven-compiler-plugin can deal with that just fine.

The point is void main, without static and without a String[] parameter.

.jpg

JEP 512 states that any of four forms of main can be used to launch a Java program. Such a method is called a launchable method.

Who cares? After all, we aren’t actively launching the main method of Spring, Quarkus, or whatever our favorite framework is. This matters to two categories of users:

.jpg

  1. Students, who won’t need to ponder the deep mystery of public static void main(String[] args)
  2. Java scripters—those intrepid people who prefer Java over bash, Python, or whatever, for small coding tasks.

Would either of these two groups of users actually want to use Maven to launch their program?

Maybe not, but this style might become more popular in general. Also, I have another marginal use case. Reviewers of the 14th edition of Core Java asked for a Maven project that would compile all of the sample programs at once. (There are over two hundred of them.)

The reviewers were keen on the Maven project so that their preferred IDE could suck in all of the sample programs at once. (Thanks to Heinz Kabutz for actually making that happen!)

I was a bit miffed, though, that one couldn’t use the Maven project to execute those sample projects, which I had mostly changed to the easier JEP 512 forms.

.jpg

The exec-maven-plugin wanted a static void main(String[] args). Seeking to escape that bed of Procrustes, it was also willing to execute the run method of a Runnable.

That’s where Maurice and myself came in. Let’s extend it to the other forms allowed by JEP 512, I said. As a motivational device, I told him that all important JEPs are powers of 2. (He was dubious, and rightly so.)

The implementation is straightforward. It just follows the JEP.

The Small Step of the Plugin

Now the exec-maven-plugin can execute all four forms of the main method, following the rules of JEP 512. (And it can still execute a Runnable.)

It is easy enough to do. Here is a POM file for a simple project:

<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
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>

   <groupId>com.horstmann.corejava</groupId>
   <artifactId>corejava-bookcode</artifactId>
   <version>1.0-SNAPSHOT</version>

   <properties>
      <maven.compiler.source>25</maven.compiler.source>
      <maven.compiler.target>25</maven.compiler.target>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   </properties>

   <build>
      <sourceDirectory>.</sourceDirectory>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.14.0</version>
            <configuration>
               <release>${maven.compiler.source}</release>
               <fork>true</fork>
            </configuration>
         </plugin>
         <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>3.6.0</version>
            <executions>
               <execution>
                  <goals>
                     <goal>exec</goal>
                  </goals>
               </execution>
            </executions>
            <configuration>
               <executable>maven</executable>
            </configuration>
         </plugin>
      </plugins>
   </build>
</project>

In the same directory as the POM file (and not a distant subdirectory src/main/java), place a file HelloWorld.java:

void main() {
    System.out.println("Hello, World!);
}

Then run

mvn install

and

mvn exec:java -Dexec.mainClass=HelloWorld

You are rewarded with:

[INFO] Scanning for projects...
[INFO]
[INFO] --------------< com.horstmann.corejava:corejava-bookcode >--------------
[INFO] Building corejava-bookcode 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- exec:3.6.0:java (default-cli) @ corejava-bookcode ---
[INFO] [stdout] Hello, World!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.883 s
[INFO] Finished at: 2025-09-30T20:11:26+02:00
[INFO] -----------------------------------------------------------------------

.jpg

That’s nice. For a Maven user.

Ok, it might not warm the hearts and minds of the readers of Core Java, and I am not pushing it on them. In the book, I strictly stick to command-line tools:

java HelloWorld.java

Note the absence of a compilation step, thanks to JEP 330 and JEP 458.

Conclusion

Since there is a Maven plugin for launching Java programs, it might as well follow the Java rules for what classes are launchabe. And now it is updated to the latest rules.

The plugin even works for programs prior to Java 25.

Just another small step for open source in action. I learned a lesson about the efficacy of hack events.

.gif

By the way, for me, the most impressive hack at that JCrete event was from Marc Hoffmann. He managed to run Java 1.0 in the browser, inside a JavaScript emulator of Windows 95. Nervous text could never be more beautiful.

Comments

With a Mastodon account (or any account on the fediverse), please visit this link to add a comment.

Thanks to Carl Schwann for the code for loading the comments.

Not on the fediverse yet? Comment below with Talkyard.