Skip to content

OpenRewrite recipe for JEP 512 instance main methods is to aggressive #890

@mvitz

Description

@mvitz

What version of OpenRewrite are you using?

I am using

  • Maven plugin v6.22.1
  • rewirte-migrate-java:RELEASE

How are you running OpenRewrite?

I am using the Maven plugin without any configuration just by running the goal via
mvn -U org.openrewrite.maven:rewrite-maven-plugin:run -Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-migrate-java:RELEASE -Drewrite.activeRecipes=org.openrewrite.java.migrate.UpgradeToJava25 -Drewrite.exportDatatables=true

What is the smallest, simplest way to reproduce the problem?

I basically found three examples when running the UpgradeToJava25 receipt, which are all related to the OpenRewrite recipe for JEP 512 instance main methods which was introduced within #852.

  1. Empty Spring Boot Project

Currently, Spring Boot, at least with Maven, when building its executable JAR file uses the public static void main(String[] args) Signature for detecting which class to use as its main entry point.

This can be reproduced by generating an empty Spring Boot Maven Project (via https://start.spring.io/#!type=maven-project&language=java&platformVersion=3.5.6&packaging=jar&jvmVersion=21&groupId=com.example&artifactId=demo&name=demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.demo&dependencies=) and executing the OpenRewrite receipt for upgrading to Java 25. Afterwards when calling mvn verify the build fails with: `

[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:3.5.6:repackage (repackage) on project demo: Execution repackage of goal org.springframework.boot:spring-boot-maven-plugin:3.5.6:repackage failed: Unable to find main class -> [Help 1]
  1. Main method is used as a method reference

The following code:

public class MainMethodReferenced {

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

    @FunctionalInterface
    interface MainMethod {
        void run(String[] args);
    }

    static void someOtherMethod() {
        MainMethod foo = MainMethodReferenced::main;
        foo.run(null);
    }
}

relies on the main-Method being static and receiving the args. But after the migration it no longer compiles.

Although, on first sight, this seems to be an unusable use-case, it is the default when using Spring Boot with Testcontainers support.
If you use start.spring.io and select testcontainers as dependency (see https://start.spring.io/#!type=maven-project&language=java&platformVersion=3.5.6&packaging=jar&jvmVersion=21&groupId=com.example&artifactId=demo&name=demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.demo&dependencies=testcontainers) by default within the test java sources a class TestDemoApplication is created that contains a main-Method that uses the real applications main-Method as a method reference.

  1. main-Method on class with non default constructor

The last use case was a CLI tool that in its main-Method creates an instance of itself and delegates to another method, like:

public class MainWithNonDefaultConstructor {

    public static void main(String[] args) {
    }
    
    public MainWithNonDefaultConstructor(String[] args) {}
}

After the receipt is run, this class compiles, but it can't be executed because a default constructor is missing.

I think 2. and 3. can probably be fixed by improving the receipt to check for the presence of a default constructor / usage as a method reference.

Number 1 is a tougher one to detect. Most likely impossible.
I would therefore suggest that the “JEP 512 instance main methods”-receipt should not be included in any Spring Boot Update receipt unless instance-main-Methods are supported by default within Spring Boot.
And most likely, not including that receipt within the UpgradeToJava25 might be a good idea, too?

Are you interested in contributing a fix to OpenRewrite?

In theory, I would, but I'm unsure if I will find the time right now.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions