Building a Maven based Spring Boot app with multiple app classes with main() methods

I have a Maven based Spring Boot project with 2 Application classes. One is my main Spring Boot app, the other is a standalone example app. When attempting to build with ‘mvn package’ I get this error:

[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.6.4:repackage (repackage) on project xample-client: Execution repackage of goal org.springframework.boot:spring-boot-maven-plugin:2.6.4:repackage failed: Unable to find a single main class from the following candidates [kh.aprs.botexample.APRSISBotExampleApplication, kh.aprs.clientexample.APRSISClientExampleApplication]

The 2 apps listed are my 2 apps, but only APRSISBotExampleApplication is the one I want to get packaged, so I need to tell Maven which is the the main app. This is configured with the <start-class> property, configured in a properties section like this:

<properties>
 <start-class>your.package.YourApplication</start-class>
</properties>

This is described here.

Calculating elapsed minutes between LocalDateTime instances

There’s many ways to this, like getting epoch millis, calculating the difference and then converting back into the units you need. With java.time apis and java.time.temporal.ChronoUnit you can calculate the difference between 2 LocalDateTime instances easily in one step with:

long elapsedMins = ChronoUnit.MINUTES.between(start, end);

I was looking for a refresher on how to do this and found my own post from 3 years ago in a Google search here (funny when that happens).

Increasing font size in menu trees in Eclipse

On a high resolution monitor, by default the tree menus that display your project contents can be too small to read. I’ve never had this issue before on older PCs/laptops/monitors, but on my M1 MacBookPro the text in menu item trees is (for me) too small to read.

The setting to increase the font size specifically for menu trees is in Preferences here: General / Appearance / Colors and Fonts / View and Editor Folders :

JEP445 Instance main() methods coming for Java 21 LTS

Java 21 is only a few weeks away from release. One of the changes that I think is the most interesting and I’m surprised that it’s taken this long to be included is JEP445 “Unnamed Classes and Instance main methods”. The goals of this JEP explain precisely the benefit of this change:

“Offer a smooth on-ramp to Java so that educators can introduce programming concepts in a gradual manner.”

“Reduce the ceremony of writing simple programs such as scripts and command-line utilities.”

“Instance main methods” refers to a change to the language requirement that the single entry point to a Java application is the main() method with this exact signature:

public void main(String[] args) {
    ...
}

…which is a lot to unpack to understand how to get started even with the most basic “Hello World” app. To explain this signature to brand new developers learning Java, I usually see the required main signature explained away with “ignore why we need this for now, just accept that you need to define the main method exactly like this for it to work” which doesn’t exactly give much comfort.

JEP445 Instance main methods allows support for much simpler main methods without the required scope, return type and params:

void main() {
...
}

To make it even easier, since this new support now allows you to use an instance method instead of the previously required Class method (static), you can call other instance methods without instantiating the class, and without understanding why you can’t call instance methods from a static method. Prevously you need to instantiate your Class first, before calling instance methods like this:

public class PreJava21App {
    public String getGreeting() {
        return "Hello World!";
    }

    public static void main(String[] args) {
        System.out.println(new PreJava21App().getGreeting());
    }
}

With JEP445 now you can code a simpler main() like this:

public class Java21App {
    public String getGreeting() {
        return "Hello World from Java 21!";
    }

    void main(){
    	System.out.println(getGreeting());
    }
}

The next change on this JEP with Java 21 introduces Unnamed Classes, so now even the Class declaration can be implicit, like this:

    public String getGreeting() {
        return "Hello World from Java 21 with implicit Classes!";
    }

    void main(){
    	System.out.println(getGreeting());
    }

Under the covers there’s still a Class, it’s implicitly named the same as the filename, so if you save the above in a file classed Java21App, then you’d run it with ‘java Java21App’.

To enable these features currently (as of OpenJDK build 21-ea+28), you need to pass the ‘–enable-preview’ param. To pass this with gradle, add the following to your build.gradle:

//pass required JVM param for compile time
tasks.withType(JavaCompile) {
    options.compilerArgs += "--enable-preview"
}

//pass required JVM param for runtime
tasks.withType(JavaExec) {
    jvmArgs += '--enable-preview'
}