Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Script generated via appassembler-maven-plugin is not able to find main class in Spring Boot application

I have a problem with the start script that I generate with appassembler-maven-plugin. I have a basic spring-boot application with only one class:

@SpringBootApplication
public class ScriptDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(ScriptDemoApplication.class, args);
    }
}

and my pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>org.home.sziolkow</groupId>
    <artifactId>script-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>script-demo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.7</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>${start-class}</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>
                                repackage
                            </goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>appassembler-maven-plugin</artifactId>
                <version>1.10</version>
                <configuration>
                    <goal>
                        package
                    </goal>
                    <showConsoleWindow>
                        true
                    </showConsoleWindow>
                    <platforms>
                        <platform>unix</platform>
                    </platforms>
                    <programs>
                        <program>
                            <mainClass>org.home.sziolkow.ScriptDemoApplication</mainClass>
                            <id>app</id>
                        </program>
                    </programs>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

I run maven with: mvn package appassembler:assemble

Package and scripts are generated but when I try to run ./target/appassembler/bin/app, I get

Error: Could not find or load main class org.home.sziolkow.ScriptDemoApplication

I tested generated packages and I can start the application without problems with:

java -jar ./target/appassembler/repo/org/home/sziolkow/script-demo/0.0.1-SNAPSHOT/script-demo-0.0.1-SNAPSHOT.jar 
like image 547
sziolkow Avatar asked Oct 08 '16 11:10

sziolkow


People also ask

What is spring boot main class?

Spring Boot allows us to define the Main class in the configuration when we have multiple main classes declared in the application. As we are using a MAVEN build, we have to configure the POM. xml for Spring Boot to identify the main class of the application.


1 Answers

You're having this trouble because of the way Spring Boot is repackaging your JAR, in order to make it an executable JAR. From the documentation:

The executable archive cannot be used as a dependency as the exectuable jar format packages application classes in BOOT-INF/classes. This means that they cannot be found when the executable jar is used as a dependency.

Essentially, the Spring Boot Maven Plugin repackages your JAR and puts your classes inside BOOT-INF/classes, all the JAR dependencies inside BOOT-INF/lib, and launches its JarLauncher class as main class, which will search for classes and JARs at those locations.

So you have 2 solutions: do not use Spring Boot to repackage your JAR into an executable JAR, or do not use the Appassembler plugin at all.

Without the Appassembler

Since Spring Boot creates an executable JAR for you, generating scripts with the Appassembler plugin is not necessary. Remove the plugin declaration for appassembler-maven-plugin and have:

<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
    <mainClass>org.home.sziolkow.ScriptDemoApplication</mainClass>
  </configuration>
  <executions>
    <execution>
      <goals>
        <goal>repackage</goal>
      </goals>
    </execution>
  </executions>
</plugin>

The only change with your POM is the addition of the <mainClass> parameter pointing to your main class, and the removal of the appassembler-maven-plugin. When launching mvn clean package, you'll be able to launch the generated executable JAR directly with:

java -jar target/script-demo-0.0.1-SNAPSHOT.jar

If the version 0.0.1-SNAPSHOT in the name of the executable is an issue, you can simply set a <finalName> in your POM:

<build>
  <finalName>${project.artifactId}</finalName>
  <!-- ... -->
</build>

and then the executable JAR will be launched with java -jar target/script-demo.jar.

With the Appassembler

As said before, since Spring Boot repackage goal put the classes and JARs inside a BOOT-INF folder, we need to get rid of that. So remove the spring-boot-maven-plugin plugin declaration, and have in your POM:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>appassembler-maven-plugin</artifactId>
  <version>1.10</version>
  <executions>
    <execution>
      <id>assemble</id>
      <goals>
        <goal>assemble</goal>
      </goals>
      <phase>package</phase>
      <configuration>
        <showConsoleWindow>true</showConsoleWindow>
        <platforms>
          <platform>unix</platform>
        </platforms>
        <programs>
          <program>
            <mainClass>org.home.sziolkow.ScriptDemoApplication</mainClass>
            <id>app</id>
          </program>
        </programs>
      </configuration>
    </execution>
  </executions>
</plugin>

The difference with your current POM is that the Appassembler is bound to the package phase, so that the execution is launched without invoking appassembler:assemble. Then, when running mvn clean package, you'll be able to start your application using the scripts generated by the Appassembler:

./target/appassembler/bin/app
like image 53
Tunaki Avatar answered Sep 25 '22 21:09

Tunaki