Neloy
Neloy

Reputation: 51

Launching main class inside a nested executable jar created with spring-boot-maven-plugin

I have a simple Spring Boot class like this:

@SpringBootApplication
public class Starter {
        public static void main(String... args) {
        if ("foo".equals(args[0])) {
            SpringApplication.run(Foo.class, args);
        } else if ("bar".equals(args[0])) {
            SpringApplication.run(Bar.class, args);
        }
     }
}

The Foo.java and Bar.java files are Main class files nested inside the current jar file as a dependency and also annotated with @SpringBootApplication. The jar file structure is shown below.

├───BOOT-INF
│   ├───classes
│   │   ├───com
│   │   │   └───app
│   │   │        └───starter
│   │   │             └───Starter.class
|   |   | 
│   │   └───config
│   └───lib
|        ├───tool1.jar
|        |    └───Foo.java
|        └───tool2.jar
|             └───Bar.java 
├───META-INF
│   └───maven
│       └───com.app.starter
│           └───starter
└───org
    └───springframework
        └───boot
            └───loader
                ├───archive
                ├───data
                ├───jar
                └───util

While this works fine from eclipse when I'm trying to launch the Starter.java but when trying to build the project with maven I'm getting exception:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project starter: Compilation failure: Compilation failure:
[ERROR] /C:/Projects/Starter/src/main/java/com/app/starter/Starter.java:[6,19] cannot find symbol
[ERROR] symbol:   class Starter

Here is the excerpt from Starter POM file:

<project>
.....
    <parent>
        <groupId>com.app.myproject</groupId>
        <artifactId>parent-tool</artifactId>
        <version>1.0</version>
    </parent>

    <artifactId>starter</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>com.app.myproject</groupId>
            <artifactId>foo-project</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>com.app.myproject</groupId>
            <artifactId>bar-project</artifactId>
            <version>1.0</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

The project structure is something like this:

I have an aggregator POM as parent project which also have declared parent as spring-boot-starter. Foo, Bar and Starter projects are all child of the parent project.

I want to make a single fat jar with all the dependencies nested with spring-boot-maven-plugin. So that I can start whichever project I want from the starter main class according to passed parameters. Is it possible with spring-boot? I have tried to call the main methods in Foo and Bar with classloader also like this but this approach is not working. Possibly I'm doing something wrong as I'm new to classloading.

URLClassLoader cl = URLClassLoader.newInstance(new URL[] {new URL("tool1.jar")});
            Class myClass = cl.loadClass("com.app.Foo");
            Method mainMethod = myClass.getMethod("main");
            Object myClassObj = myClass.newInstance();

Object response = mainMethod.invoke(myClassObj);

Can someone suggest which way to achieve this? Any ideas are really appreciated.

Upvotes: 3

Views: 2014

Answers (1)

Neloy
Neloy

Reputation: 51

Finally after a long research and with the help of my team lead, I am able to figure out the solution. It is actually an issue of executable jar dependency created by spring-boot-maven plugin. My starter class was not able to locate the Foo.java or Bar.java in dependency list because those jars are also executable jars. Finally I have added these lines in my foo-project and bar-project POM file:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <phase>none</phase>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

This makes the foo-project and the bar-project jars general ones and everything works as expected.

Hope this helps someone to work with spring-boot-maven plugin.

Upvotes: 2

Related Questions