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?
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.
Tunaki's answer is correct but doesn't work in Spring Boot 2.
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
Spring Boot 2.x
If you are using spring-boot-starter-parent, the repackage goal is executed automatically in an execution with id repackage. In that setup, only the configuration should be specified as shown in the following example:
<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
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.
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:
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.
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.
Use the build section provided below, it will do three things:
Create the spring boot jar using spring-boot-maven-plugin
Create a normal jar with your source code compiled classes using maven-assembly-plugin
Install the normal jar into the m2 folder locally
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>
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>
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>
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>
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.
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>
Related
I am trying to generate spring boot executable jar
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
And I am getting files like this one "auth_service-0.0.1-SNAPSHOT.jar", but I need to get "auth_service.jar", how can I do this?
The reference documentation for Spring Boot’s Maven plugin contains an example of how to do this:
If you need the repackaged jar to have a different local name than the one defined by the artifactId attribute of the project, simply use the standard finalName as shown in the following example:
<project>
...
<build>
<finalName>my-app</finalName>
<plugins>
...
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.2.3.RELEASE</version>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
...
</plugin>
...
</plugins>
...
</build>
...
</project>
This configuration will generate the repackaged artifact in target/my-app.jar.
I use Spring Tool Suite 4. We have a spring-boot API and we would like to create an executable (jar or war, no clue, which one i need). We have dependencies stated in pom.xml. By default this is what we have under build if you make a clean spring-boot application:
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
So my question what do i have to add so i can actually execute maven install for my executable? As of now if i run maven install (which for me the only way i know to create executable), it gives me an AssertionError. I tried to find guides online, but none of them worked.
For now i would be happy if i could even manage to execute maven install, but my plan includes the usage of config file outside of the executable also i would like to log (log4j2) next to the jar file, so i need help with those too. How to specify these in pom.xml so i can use config file from outside and to be able to log outside?
You'll want an executable jar. Add this to your pom file:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>spring-boot</classifier>
<mainClass>
specify.your.main.Class
</mainClass>
</configuration>
</execution>
</executions>
</plugin>
So I got AssertionError, because for some reason some of my tests dont work for maven (even though if i execute them they pass).
It actually matters if jar or war. In my case it has to be a war because im making an API
Also here are the minimum you have to change in pom.xml to have a chance to create executable: (this goes before dependencies inside the pom.xml)
<packaging>war</packaging>
<properties>
<java.version>11</java.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<forceJavacCompilerUse>true</forceJavacCompilerUse>
</properties>
The following part goes in between <build></build>.
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>your.main.class</mainClass>
</manifest>
</configuration>
</plugin>
<plugin>
<artifactId>maven-remote-resources-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<id>process-remote-resources</id>
<goals>
<goal>process</goal>
</goals>
<configuration>
<resourceBundles>
<resourceBundle>org.apache:apache-jar-resource-bundle:1.0</resourceBundle>
</resourceBundles>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</pluginManagement>
To sum up I still have no idea what most of these do, but this works.
I have a Java 8 Maven project that defines a custom annotation and an aspect. When running test code in that project itself, it is applying the aspect to the annotated classes. I am then packaging and installing project.
I then bring in that dependency into a new project (non-Spring). The new project is then not having the aspect applied to it's classes, though it does bring in the new annotation.
How do I have a single JAR to define an annotation and aspect and have it applied to all of my projects with Maven?
You need to specify your aspect project dependency as an aspect library in your aspectj-maven-plugin configuration in your pom.xml. Let's suppose your aspect module has the groupid:artifactid groupid:aspect-module. Your pom.xml should look similar to this:
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>groupid</groupId>
<artifactId>aspect-module</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.9</version>
<configuration>
<aspectLibraries>
<aspectLibrary>
<groupId>groupid</groupId>
<artifactId>aspect-module</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Note that I'm switching off the maven-compiler-plugin because they tend do overwrite each other's output with the aspectj-maven-plugin, and the AspectJ compiler should be able to compile normal java files and weave them in the same step anyway, so using the maven-compiler-plugin is redundant. If you are using Eclipse + AJDT, this maven configuration will much better reflect what happens in your IDE while you're developing.
Between version 1.3.8.RELEASE of the spring-boot-maven-plugin and version 1.4.0.RELEASE - there has been a change in the generated package structure (if you extract the uber jar file)
1.3.8.RELEASE com, lib, META-INF and org directories
1.4.0.RELEASE has a BOOT-INF, META-INF and org directories
Basically from 1.4.0.RELEASE onwards - all the classes and libs are in the BOOT-INF directory.
Due to this - when you try to run a Spring Boot project on Amazon Lambda - it says that there is a jar not found as it cannot read the new Spring Boot Uber jar structure
My question is - is it possible in the newer versions of the Spring Boot Maven Plugin to get it to generate the uber jar to be the same structure as in version 1.3.9.RELEASE?
I tried the maven-shade-plugin - but that leads to other issues
Any help is greatly appreciated
Thanks
Damien
The solution was to add the MODULE layout for the plugin in the pom.xml file
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layout>MODULE</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
In my case I'm using spring boot 2.X and I declared the spring-boot-maven-plugin after the maven-dependency-plugin (which I used to unpack and create exploded app in Docker) and it must be before the unpack, makes sense, it was unpacking before the spring boot maven plugin executed. Next time I'll declare it first thing in the plugin chain, lost more than 1 hour on this. Hope it helps someone.
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>${spring.boot.mainClass}</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
The answer above with
<layout>MODULE</layout>
does not work anymore, this is because layout element is deprecated in Spring Boot 2.x.
I am using Spring Boot 2.0.x, I found this helpful comment on github:
Support for the module layout was removed in Spring Boot 2.0 having been deprecated in 1.5. Unfortunately, the updates to the Maven Plugin's documentation were missed so we can use this issue to sort that out. You should use a custom LayoutFactory instead.
But as I did not want to implement LayoutFactory I tried this second solution below that actually repackage and creates an extra jar with a classifier given name:
This is due to the change in layout of executable jars in Spring Boot 1.4. Application classes are now packaging in BOOT-INF/classes.
Your client module depends on the repackaged, fat jar of your web module. Due to the new layout that means that the client module can no longer load the web module's classes. If you want to use your web module as a dependency, you should configure Boot's repackaging to apply a classifier to the fat jar. For example:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Doing so will allow other modules to depend on the original jar that does not embed the module's dependencies and has the classes at the root of the jar.
One original jar have the same structure as I wanted like
com.my-package.foo.bar
META-INF
and the second classifier have the newer structure with BOOT-INF/ etc.
For me, the solution was a bit more insidious....I had the spring-boot-maven-plugin nested under pluginManagement, (see below). Doh!
The nasty thing, is that when I'd run mvn spring-boot:run, spring boot comes up just fine, and runs app! It wasn't until we tried to deploy to PCF (as a spring-boot JAR), that we'd get an error that there was something wrong with format of the binary....
<build>
<!--
DON'T DO THIS!!
-->
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<!--
DO THIS INSTEAD!!
-->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Once I removed the pluginManagement tags from the POM, I would now get the ./BOOT-INF structure. Please keep in mind that pluginManagement is typically for a parent-pom structure, where you want that plugin's config used across other modules.
I was using Gradle, instead of Maven, and this is what I had to do:
1- In my build.gradle, I added the following properties as defined in https://spring.io/guides/gs/spring-boot-Docker/.
buildscript {
...
dependencies {
...
classpath('gradle.plugin.com.palantir.gradle.docker:gradle-docker:0.13.0')
}
}
group = 'springio'
...
apply plugin: 'com.palantir.docker'
task unpack(type: Copy) {
dependsOn bootJar
from(zipTree(tasks.bootJar.outputs.files.singleFile))
into("build/dependency")
}
docker {
name "${project.group}/${bootJar.baseName}"
copySpec.from(tasks.unpack.outputs).into("dependency")
buildArgs(['DEPENDENCY': "dependency"])
}
2- My dependency folder was not being written to
ARG DEPENDENCY=target/dependency
instead, I located it in another folder, so I changed this property in the Dockerfile:
ARG DEPENDENCY=build/dependency
With this I got a successful build.
I have following project structure:
Project "parent-project" does not have any source file and has subprojects as "junit-wrapper","child1-test" and "child2-test".
Subproject "junit-wrapper" has only java source inside src/main/java and this is basically created to wrap all the dependencies and binaries under the hierarchy "parent-project".
Subproject "child1-test" and "child2-test" has no source files and only contains subprojects as "child1-env" and "child2-env".
Subproject "child1-env" and "child2-env" has only junits inside src/test/java.
I want to build a super jar(within junit-wrapper) by building parent pom.xml
I hope this is possible by using maven-assembly-plugin but don't know how to configure this in pom.xml. what should be my pom.xml or assembly.xml(on using plugin) entries in order to ensure this is achieved?
please suggest.
thanks.
To create a jar which contains test-classes the best solution is to use the maven-jar-plugin like this:
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
In other modules you can use the test-jar via the following dependency:
<project>
...
<dependencies>
<dependency>
<groupId>com.myco.app</groupId>
<artifactId>foo</artifactId>
<version>1.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
...
</project>
You will get your "uber-jar" when you include this configuration into the pom file of junit-wrapper:
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
An assembly descriptor (assembly.xml) is not necessary because the jar-with-dependencies descriptor is already available within the maven-assembly-plugin. Note that you should not execute the assembly plugin before the package phase. Otherwise the code of your maven module will not get packaged into your assembly.