Problem creating a thin jar in Spring Boot Maven project - java

I have a Maven Spring Boot Micro Services Java project arranged into a parent module and 6 sub-modules. In the parent pom.xml, I have included the Maven Spring Boot Plugin in the build/plugins section: -
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.5.RELEASE</version>
</plugin>
5 of my 6 sub-modules are Micro Services, and the above plugin ensures that these are built into executable Spring Boot jars, including all dependencies, when I run mvn clean install
However, the other sub-module is just a standard Java utility project and does not have a Spring Boot context. When I try to build, I see the following error: -
Execution repackage of goal org.springframework.boot:spring-boot-maven-plugin:2.1.5.RELEASE:repackage failed: Unable to find main class -> [Help 1]
This is expected as this sub-module is not a Spring Boot application and does not have a main class. I tried to fix this by overriding the Spring Boot Maven plugin in the pom file of that sub-module so that it is treated as a standard 'thin' jar: -
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<dependencies>
<!-- The following enables the "thin jar" deployment option. -->
<!-- This creates a normal jar, not an executable springboot jar -->
<dependency>
<groupId>org.springframework.boot.experimental</groupId>
<artifactId>spring-boot-thin-layout</artifactId>
<version>1.0.11.RELEASE</version>
</dependency>
</dependencies>
</plugin>
However, I am still seeing exactly the same error in my Maven build. I would be most grateful for any hints or pointers on this one.

You can skip the execution of the repackage plugin for your utility module by overriding the configuration in that module.
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>

Related

Maven jandex plugin does not generate index for local custom maven repositories (sometimes)

I have a multi module maven project wie quarkus modules and some custom libraries which are local maven repositories (so they can be used by the other maven projects/modules). However, so that local maven repositories are recognizable und usable by your other local maven projects, you have to manually index them for some reason. I.e. add a config like this for quarkus index to the application.properties of the project including the local maven repo dependency:
quarkus.index-dependency.<index-name>.group-id = <group-id-of-local-maven-repo>
quarkus.index-dependency.<index-name>.artifact-id = <artifact-id-of-local-maven-repo>
The problem is, this causes issues for me becausse if you have 3 layers of project dependencies, say:
Project A (custom local maven repo library)
Project B (custom local maven repo library, includes Project A dependency)
application.properties (indexing Project A library dependency)
Project C (Local maven project for an end product, includes Project B
library dependency - and through it indirectly Project A).
application.properties (indexing Project B library dependency and config for datasources or other app related things)
Then when you generate an uber-jar (fat jar) of Project C for deployment, it for some reason uses application.properties of Project B in the packaged jar, instead of from the project which im building (Project C). Thus, the app is missing key configs and does not work. Maven seems to use an inverse priority here, which i dont know if thats a bug or not. When i asked about this, i was simply told that:
"My dependencies should not have application.properties".
I tried to find a way to prevent manual indexing via application.properties and found the maven jandex plugin - which is supposed to generate an index. The next problem is, this seems to only work in some projects but not in others in the dependency hierarchy, resulting in the same situation as before, and i don't understand why. This is the pom.xml config for the plugin i have included in all 3 projects (the entire pom.xml for all is too long, so let me know if you need more info):
<properties>
...
<jandex.skip>false</jandex.skip>
...
</properties>
...
<build>
...
<plugin>
<groupId>io.smallrye</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>3.0.5</version>
<inherited>true</inherited>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
<configuration>
<skip>${jandex.skip}</skip>
</configuration>
</plugin>
...
The odd thing is, this works to the extend that i no longer have to index Project B library dependency in Project C application.properties, but Project B library dependency still has to manually index Project A library dependency - thus rendering the entire exercise futile. Project C having an application.properties was never the issue, and is obviously needed. Project B still requires a properties file to point to Project A now, how do i solve this?
I have a parent module POM in the root folder containing all these projects, over which this maven jandex dependency is distributed to all modules, so it looks like this:
Maven parent module (contains all dependencies and versions used by all project sub modules)
Project A (custom local maven library repo), own pom.xml with inheritance from parent module
Project B (custom local maven library repo, includes Project A library), own pom.xml with inheritance from parent module
application.properties - Indexes Project A dependency manually, this is the problematic one which needs to go!
Project C (Local maven project for REST API etc., includes Project B library), own pom.xml with inheritance from parent module
pom.xml (parent module POM, containing maven jandex dependepency among others)
Edit: One of the projects, "entity", where all the database access objects are stored, does not run the jandex plugin during mvn clean install. This is the POM of the project:
<?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>com.compamny.project</groupId>
<artifactId>entity</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm</artifactId>
<version>2.16.1.Final</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-validator</artifactId>
<version>2.16.1.Final</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
<version>2.16.1.Final</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.13.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.smallrye/jandex-maven-plugin -->
<dependency>
<groupId>io.smallrye</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<plugin>
<groupId>io.smallrye</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>3.0.0</version>
<inherited>true</inherited>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
When i force the execution of the jandex goal with mvn io.smallrye:jandex-maven-plugin:3.0.0:jandex it creates an META-INF/jandex.jdx file, but it does not produce one when i run mvn clean install. This is not a solution since i need to build the project, run the jandex plugin and install it into my local repositories separately. Also, notice that im using the "io.smallrye" version of the jandex plugin since the "org.jboss" version seems to not work at all.
I figured it out. The jandex plugin was set in the <pluginManagement> section of the POM configuration, which made it not run on mvn clean install. I had to move it to the plugins section so it gets executed. Thanks #Ladicek for making me look closer and keep trying!

Spring boot maven plugin: mvn clean package does not layered jar file automatically

I got trouble with spring-boot-maven-plugin build process. I just want to build
excutable "layered" jar file for optimizing docker image. As document said this build process will produce layered jar by default https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/. Here is apart of my pom.xml file
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layers>
<enabled>true</enabled>
</layers>
</configuration>
</plugin>
</plugins>
</build>
I used spring boot 2.5.5, maven 3.6.3
Some steps produce:
mvn clean package
jar -tf target/[excutableJarFile].jar
This filesystem of excutableJarFile is just BOOT-INF, META-INF and org although it should be
dependencies
spring-boot-loader
snapshot-dependencies
application
Enabling the layering feature of the Spring Boot Maven plugin does not change the layout of the generated jar file. It does enable the generation of a layers.idx file that describes how the application is layered, as described in the Spring Boot documentation.
You can use the layertools mode of the generated jar to extract the contents of the jar into a layered structure. See the Dockerfile example in the documentation for more information on how this works.

Can run spring boot application from eclipse but not from terminal

I have a problem with a Spring boot project, it has another spring boot project as a dependency in its pom.xml.
I can run it properly using eclipse, but an error shows up when I try to run it with terminal using the command mvn spring-boot:run.
[ERROR] Failed to execute goal on project platform-service: Could not resolve dependencies for project com.test.platform:platform-service:jar:0.0.1-SNAPSHOT: Could not find artifact com.test:student-service:jar:exec:0.0.1-SNAPSHOT
This is how I added the dependency in pom.xml :
<dependency>
<groupId>com.test</groupId>
<artifactId>student-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
I have tried different solutions like mvn package spring-boot:repackage but it didn't work.
Thank you so much.
Add this plugin after dependencies in pom.xml
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Save this and run again.

Cannot compile with maven while importing a local project as dependency

I'm creating a common library that will be used accross several Spring application. I've extracted the common classes I want to share between these application into a new Spring application named "Common". I've used mvn install on this application to put it in my local maven repository. On my main project, I've added the maven dependency, with the same version, in the pom.xml.
Now, if I try to launch mvn compile on my main project, I got this error :
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project recruitment: Compilation failure: Compilation failure:
[ERROR] /D:/[...]/application/src/main/java/com/example/application/service/Service.java:[8,37] package com.example.common.exception does not exist
Indicating that my common library is not present and thus my application cannot find package coming from it.
If I try to launch my Spring application from the main (using Spring Boot), it launchs perfectly and behaves like before.
I'm using IntelliJ on Windows, maven is bundled with IntelliJ with the default installation. If I check in my local maven repository I can find the common library jar. IntelliJ does not show any error on my imports, it recognizes my library.
There seem to be some conflict between IntelliJ, which read the pom.xml to find libraries imported for my application, and maven that use the same pom.xml to compile my code.
I used mvn compile -X to have more information and the funny part is that maven is using the common library jar from the local repository :
[INFO] Changes detected - recompiling the module!
[DEBUG] Classpath:
[DEBUG] D:\[...]\application\target\classes
[DEBUG] C:\[...]\.m2\repository\com\example\common\0.0.1\common-0.0.1.jar
Do you have any idea why I can't compile my project with maven while
I can launch it as a Spring application ?
Here is my dependency in my pom.xml :
<dependency>
<groupId>com.example</groupId>
<artifactId>common</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
And the common library definition :
<groupId>com.example</groupId>
<artifactId>common</artifactId>
<version>0.0.1</version>
<name>common</name>
<description>Common project with generic technical modules</description>
Okay, that's embarassing... I just found the solution ! It has been two days looking for a solution to this tricky situation and I just found what was missing, or rather what was too much.
This bad boy :
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
The Spring boot maven plugin is what makes my Spring boot application launchable from maven, and it seems that it affects the way the common jar library is made, or the way it is imported.
I don't really understand why exactly it affects my import, but I deleted the plugin above in my common library pom.xml, I reinstalled in my local repository and I launch mvn install again on my main application... And it now works !
I think that launching via Spring boot used a little bit of Spring boot magic to make it works that the maven way lacks.
If someone understands it better and can explain it, that would be great and the accepted answer I think.
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
Proper config will look like:
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.1.RELEASE</version>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Taken from
https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/html/#repackage-examples

Jenkins Maven Plugin: Classloading Feature

Good time!
Our team uses Maven. One of the project modules has a plugin (maven-jibx-plugin) that requires (for our use-case) a dependency on a proprietary jar:
<plugin>
<groupId>org.jibx</groupId>
<artifactId>jibx-maven-plugin</artifactId>
<version>${jibx.version}</version>
<executions>
<execution>
<id>main-schemas</id>
<phase>generate-sources</phase>
<goals>
<goal>schema-codegen</goal>
</goals>
<configuration>
<schemaLocation>
...
</schemaLocation>
<includeSchemas>
...
</includeSchemas>
<customizations>
<customization>${basedir}/src/main/resources/customizations/customization.xml
</customization>
</customizations>
<verbose>true</verbose>
</configuration>
</execution>
<execution>
<id>bind</id>
<phase>process-classes</phase>
<goals>
<goal>bind</goal>
</goals>
<configuration>
<schemaBindingDirectory>
${basedir}/src/main/resources/bindings
</schemaBindingDirectory>
<includeSchemaBindings>
<includeSchemaBinding>*.xml</includeSchemaBinding>
</includeSchemaBindings>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>proprietary-jar</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</plugin>
The problem is when we build the project locally (and even from a command line on the remote machine where jenkins is istalled), everything builds successfully, but when our jenkins instance tries to build it - the build fails with such a message: "Unable to find class 'class-name-from-the-proprietary-jar'". This problem occurred loccally before we added the plugin dependency..
Seems like there is some feature of jenkins maven plugin that do no resolve the plugin dependencies or may be there are some well-known feature of the jenkins maven plugin classloading (JiBX loads proprietary classes with such a construct: SchemaRootBase.class.getClassLoader().loadClass(cname) So that specifing the dependency for the plugin should provide a knowledge for it about the required classes)... Can somebody, please, suggest the workaround?
UPDATE:
it turned out that the jenkins instance's JAVA_HOME variable is set to /usr/java/jdk1.7.0_25, but in my maven-compiler-plugin I have <target>1.6</target>. Could it be that the problem is in the 1.7 java version?
Well, finally I've found an answer! The problem is not actually in Jenkins, but rather in Maven itself.
ATTENTION: the undergoing information is tested only for Maven 2.
It turned out that when you have a multimodule project and several modules use the same plugin (with different dependencies), Maven would get dependencies set for the first plugin (I mean that the plugin is located in the first module, that Maven builds, with this plugin) and use them for other plugins not overriding the dependencies by the local values.
To clarify this lets have an example. Say there are two modules in the maven build - A and B:
<modules>
<module>A</module>
<module>B</module>
</modules>
and the module A has such the code in the pom file:
<plugin>
<dependencies>
<dependency>
<groupId>com.c</groupId>
<artifactId>D-module</artifactId>
<version>1</version>
</dependency>
</dependencies>
<groupId>org.jibx</groupId>
<artifactId>jibx-maven-plugin</artifactId>
<version>${jibx.version}</version>
</plugin>
and the module B has such the code in the pom file:
<plugin>
<dependencies>
<dependency>
<groupId>com.c</groupId>
<artifactId>F-module</artifactId>
<version>1</version>
</dependency>
</dependencies>
<groupId>org.jibx</groupId>
<artifactId>jibx-maven-plugin</artifactId>
<version>${jibx.version}</version>
</plugin>
It turns out that when Maven builds the module B it will use the D-module dependency even though you have specified the F-module dependency.
In our project we made such a workaround: we moved the plugin declaration to the parent pom in a pluginManagement section and declared the D-module and F-module dependencies for the plugin (also removed these dependencies from the local modules). Ok, the code is rather ugly (having child dependencies in the parent pom file), but this works!
If somebody shared this issue and managed to overcome it, please, advice the solution.
Try mvn clean install in your workspace
Then you should have the same error every where. Also try and use the same command line Jenkins is using (if any)

Categories