How to add a dependency to a Spring Boot Jar in another project?
Asked Answered
P

12

73

I have a Spring Boot application and I have created a Jar out of that. Following is my pom.xml:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-java8time</artifactId>
        <version>2.1.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!-- WebJars -->
    <dependency>
        <groupId>javax.mail</groupId>
        <artifactId>mail</artifactId>
        <version>1.4.7</version>
    </dependency>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.6.2</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

I want to use this Jar in my other application so added this jar to my application. But when I am calling a method in that Jar, it is throwing a ClassNotFoundException.

How can I fix this issue? How can I add a dependency to a Spring Boot JAR?

Pleopod answered 17/10, 2016 at 14:46 Comment(2)
You cannot use a spring-boot-plugin-manipulated-jar as a "normal" dependency, as its structure has been changed to be "startable" as a standalone JAR for Spring. I would suggest to extract the code needed in both apps in a separate non-Spring-boot (so traditional library JAR) module.Schmitz
For Spring Boot 2: https://mcmap.net/q/272250/-how-to-add-a-dependency-to-a-spring-boot-jar-in-another-projectYurik
F
122

By default, Spring Boot repackages your JAR into an executable JAR, and it does that by putting all of your classes inside BOOT-INF/classes, and all of the dependent libraries inside BOOT-INF/lib. The consequence of creating this fat JAR is that you can no longer use it as a dependency for other projects.

From Custom repackage classifier:

By default, the repackage goal will replace the original artifact with the repackaged one. That's a sane behaviour for modules that represent an app but if your module is used as a dependency of another module, you need to provide a classifier for the repackaged one.

The reason for that is that application classes are packaged in BOOT-INF/classes so that the dependent module cannot load a repackaged jar's classes.

If you want to keep the original main artifact in order to use it as a dependency, you can add a classifier in the repackage goal configuration:

<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <version>1.4.1.RELEASE</version>
  <executions>
    <execution>
      <goals>
        <goal>repackage</goal>
      </goals>
      <configuration>
        <classifier>exec</classifier>
      </configuration>
    </execution>
  </executions>
</plugin>

With this configuration, the Spring Boot Maven Plugin will create 2 JARs: the main one will be the same as a usual Maven project, while the second one will have the classifier appended and be the executable JAR.

Finegan answered 17/10, 2016 at 15:0 Comment(8)
So when running 'mvn clean install' the jar file suitable for use as a dependency will be the one added to the .m2 repository?Kentkenta
Is anyone aware how to do similar in Gradle (NB : I am completely new to gradle)Invincible
@Gourabp bootRepackage { classifier = 'exec' }Eustis
Spring Boot 2 has a new Gradle plugin with bootJar and bootWar task instead of bootRepackage. See also docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/…High
For maven plugin users, please follow docs.spring.io/spring-boot/docs/2.2.0.RELEASE/maven-plugin/…Caenogenesis
what is BOOT-INFTurgot
@Tunaki, I have the same plugin at my pom but when building I receive the following error message: no main manifest attribute in xyz.jar. Any ideas?Bret
The execution id is essential: <id>repackage</id>.Dissatisfied
Y
33

If you are using spring-boot-starter-parent, such execution is already pre-configured with a repackage execution ID so that only the plugin definition should be added.

Spring Boot 3.x

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Read more


Spring Boot 2.x

  <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
      <execution>
        <id>repackage</id>
        <configuration>
          <classifier>exec</classifier>
        </configuration>
      </execution>
    </executions>
    ...
  </plugin>

Read more


Spring Boot 1.x

  <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>1.5.20.RELEASE</version>
    <executions>
      <execution>
        <goals>
          <goal>repackage</goal>
        </goals>
        <configuration>
          <classifier>exec</classifier>
        </configuration>
      </execution>
    </executions>
    ...
  </plugin>

Read more

Yurik answered 17/4, 2019 at 7:27 Comment(1)
This worked with Spring Boot 2.6.4. Thanks!Jill
G
5

For Spring Boot 2 @Tunaki's answer must be modified a bit according to the documentation if spring-boot-starter-parent is used as parent :

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
      <execution>
        <id>repackage</id>
        <configuration>
          <classifier>exec</classifier>
        </configuration>
      </execution>
    </executions>

Take note of the extra <id>repackage</id> necessary to overwrite to execution from the spring-boot-starter-parent.

Goldarn answered 10/4, 2019 at 20:31 Comment(0)
P
4

if you want to use the spring-boot project as a dependency and same time want to run as a spring-boot jar then use the below configuration. by the below configuration, you can achieve two goals.

      <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <id>build information</id>
                    <goals>
                        <goal>build-info</goal>
                    </goals>
                </execution>
                <execution>
                    <id>repackage</id>
                    <configuration>
                        <classifier>exec</classifier>
                    </configuration>
                </execution>
            </executions>
        </plugin>

This configuration creates two jars as shown below example screenshot:

enter image description here

Phlebotomy answered 30/3, 2021 at 16:59 Comment(1)
This answer is excellent and I feel it best answers the question of "How do I configure my build to create both an executable jar and a dependency jar that can be imported without causing ClassNotFoundException"Amphibole
L
2

What @Tunaki stated was mostly correct but the one missing part based on your original question was:

This throwing ClassNotFoundException. The External jar's used in spring boot application is missing.

This is due to the fact that the FatJAR created from the maven packaging has the dependent libraries specified in a specific location that works for how Spring Boot executes the application. If you are just adding the JAR to another application's classpath then you should do what @Tunaki said and also include the dependent JAR files to the classpath. The best way to work with this is to use the Maven Dependency Plugin specifically targetting the dependency:copy-dependencies mojo to download all the dependencies into a folder that you can then specify as a library path when compiling the other application.

Lebaron answered 18/10, 2016 at 6:37 Comment(0)
R
2

You can extend your project by maven-assembly-plugin

<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.1.0</version>
        <configuration>
        <descriptorRefs>
                <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        </configuration>
        <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
            <goal>single</goal>
            </goals>
            </execution>
        </executions>
</plugin>

After the build you will get 3 jars. The main one will be the same as a usual Maven project, while the second one will have the classifier appended with exec and be the executable JAR. The third jar name will be appended by jar-with-dependencies and will contain your classes with classes added as dependencies in your spring boot application(spring-boot-starter-web, thymeleaf,...), so into the pom of the application where you want to add that project as dependencie you won't have to add dependencies from spring boot project.

Redivivus answered 4/2, 2018 at 10:38 Comment(0)
B
2

Use the build section provided below, it will do three things:

  1. Create the spring boot jar using spring-boot-maven-plugin
  2. Create a normal jar with your source code compiled classes using maven-assembly-plugin
  3. Install the normal jar into the m2 folder locally
  4. If you want to deploy the normal jar into a remote repository, configure the deploy plugin

    <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">
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <appendAssemblyId>true</appendAssemblyId>
                            <descriptors>
                                <descriptor>src/main/resources/sources-jar-build.xml</descriptor>
                            </descriptors>
                            <finalName>${pom.artifactId}-${pom.version}</finalName>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-install-plugin</artifactId>
                <executions>
                    <execution>
                        <id>install-file</id>
                        <goals>
                            <goal>install-file</goal>
                        </goals>
                        <configuration>
                            <file>${pom.artifactId}-${pom.version}</file>
                            <artifactId>${pom.artifactId}</artifactId>
                            <groupId>${pom.groupId}</groupId>
                            <version>${pom.version}</version>
                        </configuration>
                    </execution>
                </executions>               
            </plugin>
        </plugins>
    </build>
    


Place the below content in a file named "sources-jar-build.xml", into resources folder:

<assembly
    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
    <id>sources</id>
    <includeBaseDirectory>false</includeBaseDirectory>

    <formats>
        <format>jar</format>
    </formats>
    <fileSets>
        <fileSet>
            <directory>${project.basedir}/target/classes</directory>
            <outputDirectory>/</outputDirectory>
        </fileSet>
    </fileSets>
</assembly>
Boggess answered 22/7, 2019 at 19:42 Comment(0)
D
1

use below plugin for spring boot version 2.*

<plugin>
     <groupId>org.springframework.boot</groupId>           
     <artifactId>spring-boot-maven-plugin</artifactId>
     <version>2.2.1.RELEASE</version>
     <configuration>
          <classifier>exec</classifier>
     </configuration>
</plugin>
Darter answered 5/2, 2020 at 5:8 Comment(0)
S
1

All existing answers are made under the assumption that the Spring Boot project upon which another project should depend is an application, which is fair enough since the question is phrased like that.

But if the underlying project is meant to be used as a library only, i.e. it contains no (sensible) Main class, there is obviously no executable code that needs to be repackaged at all.

So in that case, it makes more sense to skip the repackaging entirely like this:

<plugins>
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <executions>
            <execution>
                <id>repackage</id>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </execution>
        </executions>
    </plugin>
</plugins>
Stir answered 15/3, 2022 at 14:33 Comment(0)
L
0

I used version 2.2.5 and it's working. add it to your pom.xml

<plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.2.5.RELEASE</version>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <configuration>
                            <classifier>exec</classifier>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
Likelihood answered 30/9, 2021 at 9:37 Comment(0)
C
-1

You can setup your projects so that the batch launcher relies on a jar, which would be shared with your other application.

Said differently, as per your initial request :

I want to use this Jar in my other application so added this jar to my application.

Let's say your jar is your project A, and your application is your project B.

Now, what I suggest, is that you remove the launching part from A ; then you put it into a new project C, that would embed Spring Boot, and that would rely almost totally on A.

Then, since A is now a simple jar, B can use it as a dependency.

Canadian answered 10/4, 2017 at 9:55 Comment(0)
N
-1

any project if you want add as a dependency you need that project <groupId>,<artifactId>,<version>, with these details you can add your project as a dependency in another module or application for ex: your application pom details

<project 
        <groupId>com.sample</groupId>
        <artifactId>sampleapp</artifactId>
        <version>1.0</version>
        <packaging>jar</packaging>
</project>`

your dependency as like below

 <dependency>
 <groupId>com.sample</groupId>
 <artifactId>sampleapp</artifactId>
 <version>1.0</version>
</dependency>
Neuritis answered 9/10, 2018 at 7:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.