Can we configure Spring Boot Executable Jar? - java

I have a spring boot application based on maven and has several modules. I do use a spring-boot-maven-plugin, however, this plugin is only used on one of the modules. Even though the individual jar files for each modules are pretty small, the executable produced by the main module where I use this plugin with "repackage" goal is pretty large (About 750 MB).
I expanded the jar file that is created and was a little surprised to see that that it has bundled the jar files for several operating systems such as windows, linux, android etc.
If you see the opncsv jar file in the screenshot below, it appears it has bundled those jars for 13 different Operation systems !!
I understand that the executable created this way will be runnable in cross platforms, but just wondering if there is a way to configure this executable creation so that it only packages for certain OS only such as linux where I am running this app on.
The large executable just seems like an overkill in my situation.
Here is the plugin
<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>
<mainClass>org.blabla.products.webapp.Application</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Here are the dependency versions of different jars that i am using.
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<mysql-connector-java.version>5.1.40</mysql-connector-java.version>
<!--CHECKED FOR CURRENCY AND UPGRADED AS NEEDED ON 1/27/2019-->
<findbugs-maven-plugin.version>3.0.5</findbugs-maven-plugin.version>
<jacoco-maven-plugin.version>0.8.2</jacoco-maven-plugin.version>
<springfox-swagger2.version>2.9.2</springfox-swagger2.version>
<org.jsoup.version>1.11.3</org.jsoup.version>
<opencsv.version>4.4</opencsv.version>
<httpclient.version>4.5.6</httpclient.version>
<dl4j.version>1.0.0-beta3</dl4j.version>
<spring-web.version>5.1.4.RELEASE</spring-web.version>
<gson.version>2.8.5</gson.version>
<ehcache.version>3.6.3</ehcache.version>
<guava.version>27.0.1-jre</guava.version>
<thymeleaf-extras-springsecurity4.version>3.0.4.RELEASE</thymeleaf-extras-springsecurity4.version>
</properties>

I guess you can try to exclude it with maven. This was already answered here.

Related

How do I change frontend folder location and configure it in Vaadin14?

How do I change the default frontend folder location in a maven Vaadin 14 project from ${project.basedir}/frontend to ${project.basedir}/src/main/frontend?
Also, Vaadin plugin outputs frontend folder in maven build output directory instead of the war exploded directory, where I would expect it to be.
How do it make it to work since I did not map this folder into my web.xml file?
How do I make it put frontend folder into the war archive and see which configuration it is using to make the compiled front end visible to my application?
Vaadin uses the frontend folder differently in both dev and production modes. In production it builds the frontend using the build-frontend goal. Vaadin Maven Plugin don't have a proper documentation, the best place I found explaining what each goals do is here: https://vaadin.com/docs/v14/flow/production/tutorial-production-mode-advanced.html. This page explains that build-frontend is responsible for building and putting the frontend processed into WEB-INF\classes\META-INF\VAADIN\build when in production mode.
Dev mode is very different, development instructions explains that if you don't use an embedded server you should configure your IDE to run prepare-frontend goal before deployment: https://vaadin.com/docs/v14/flow/workflow/run-on-server-intellij.html. But prepare-frontend just creates the empty frontend folder into target, how does it find frontend files if the folder is empty and nothing is copied to the war exploded folder? Answer: when you run the application, Vaadin has a DevModeInitializer that creates the file generated-flow-imports.js into target/frontend, which refer directly to the project source files, so that any modifications made at them may be reflected immediately, and that's why there is no need of any configuration in web.xml or context listener.
Dev mode make kind of a hack with frontend folder to make development smoother, and prod mode compile everything from frontend into a minified file served by the Vaadin servlet, so only in prod mode frontend goes into the war file. In the first case, prepare-frontend must be used, in the second, build-frontend must be used also. So, in order to modify the frontend folder location, one must change the plugin configuration in those two goals:
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
<version>${vaadin.version}</version>
<executions>
<execution>
<goals>
<goal>prepare-frontend</goal>
</goals>
</execution>
</executions>
<configuration>
<frontendDirectory>${project.basedir}/src/main/frontend</frontendDirectory>
</configuration>
</plugin>
<profiles>
<profile>
<!-- Production mode is activated using -Pproduction -->
<id>production</id>
<properties>
<vaadin.productionMode>true</vaadin.productionMode>
</properties>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>flow-server-production-mode</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-frontend</goal>
</goals>
<phase>compile</phase>
</execution>
</executions>
<configuration>
<frontendDirectory>${project.basedir}/src/main/frontend</frontendDirectory>
</configuration>
</plugin>
</plugins>
</build>
</profile>
That way, the modification will work in both dev and production mode.

Maven Modules assembly/shade build

I have the following module structure:
powercontrol
powercontrol-core
pom.xml
powercontrol-data
pom.xml
powercontrol-gui
pom.xml
powercontrol-ui
pom.xml
pom.xml
Now I want that the GUI (Graphical User Interface) and UI (Command Line User Interface) can be executed by the client.
I tried to use the maven shade plugin inside the GUI and UI, but this makes it really a mess.
I prefer:
A jar file with all the third party dependencies (log4j etc).
A jar file (or maybe lib folder?) with all the project modules.
A'n executor for the GUI and UI.
Example:
powercontrol/
bin/
gui
ui
lib/
third-party.jar
powercontrol-core.jar
powercontrol-data.jar
powercontrol-gui.jar
powercontrol-ui.jar
I'm a bit stuck with getting a good structure now, where should I start?
All feedback, suggestions etc are welcome. Thank you in advance!
UPDATE 8/28/2015
I made a new module named: powercontrol-dist that will be executed as last in the Maven lifecycle. This module will generate a lib folder and copy all the dependencies from the powercontrol-gui and powercontrol-cli to this folder.
Now I have 2 questions!
Question 1
Is this a good way to go? Or is there a better way?
powercontrol-dist/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>
<parent>
<groupId>nl.nberlijn.powercontrol</groupId>
<artifactId>powercontrol</artifactId>
<version>1.0</version>
</parent>
<artifactId>powercontrol-dist</artifactId>
<packaging>pom</packaging>
<name>PowerControl Dist</name>
<description>Dist</description>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>powercontrol-gui</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>powercontrol-cli</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Output:
powercontrol/
bin/
gui.exe
ui.exe
lib/
third-party-lib.....jar
third-party-lib.....jar
third-party-lib.....jar
powercontrol-core.jar
powercontrol-data.jar
powercontrol-gui.jar
powercontrol-cli.jar
Question 2
Also I want to make two .exe files "gui.exe and cli.exe" referencing to the powercontrol-gui.jar and the powercontrol-cli.jar.
Is adding a mainclass to the manifest inside the pom.xml in the powercontrol-gui and powercontrol-cli module enough?
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>${main.class}</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
If you want two executable JARs (gui.jar, ui.jar), you should add the shade plugin to those two modules, so that as part of each module, a standalone executable JAR is built. Both of the JARs will contain all the third-party stuff as well. You cannot create a standalone executable JAR where parts of the dependencies are in an external JAR (unless you do you own classloader magic or unless you also have to specify the external JAR on the command line).
If you are stuck with the maven shade plugin, you should tell us what problem exactly you have. Typically these can be resolved. A common problem is that certain files need to be "merged" when a shaded JAR is created, in particular files in META-INF e.g. used by Spring or by the Java Service Locator mechanism. The shade plugin offers support for such merging, but it needs to be configured for the case at hand.
Btw. I'd recommend calling the command line version "cli.jar" - "ui" sounds like "gui".
Ok, since you updated your question and now seem to be asking for a "native launcher" (exe file) instead of an executable JAR file - those are completely different things.
Launching an exe file from the command line:
C:\> gui
Launching an executable JAR file from the command line
C:\ java -jar gui.jar
To get the first, you need to create a native launcher that internally invokes Java. A project that might support you in that task could be launch4j - they also seem to provide a Maven plugin.

Can Maven Deploy a Module to JBoss?

We have a Maven project that we are using to deploy several wars to a JBoss server. We recently noticed that one of the jars that a couple of our wars depend on, uses Xerial. When Xerial starts it tries to load up a native driver, but only the first one successfully loads the native driver and the rest fail and fall back on a pure Java implementation because the native driver is already in a classloader. We would really like to gain the performance back by being able to load the native driver on all the wars.
It looks to me like the best way to do this would be add the jar we depend on to the JBoss server as a module, and then have the services depend on it.
My question is, is there a way we can get our Maven build to do this? Or are we going about this in the completely wrong way?
After a few days of looking, and talking to a couple of people who were much more familiar with JBoss-Maven interaction than me, it turns out the answer to my question is that it cant currently be done. There is no Maven plugin capable of deploying a Module to JBoss. This is largely in part to the fact that the modules are only loaded by JBoss when it starts, although if anyone is feeling particularly ambitious and wants to write their own Maven plugin, it could theoretically be worked around.
The answer #Robert Scholte left is a good one, and I learned from it, however it didn't actually answer my question.
First and most of all Apache Maven is a build management tool. It will "package" a project and will normally upload it to a repository so it can be used by other projects.
However, there are plugins available, which can deploy to JBoss:
http://mojo.codehaus.org/jboss-maven-plugin/ (maybe combined with http://mojo.codehaus.org/jboss-packaging-maven-plugin/ )
http://cargo.codehaus.org/
The first is JBoss specific, the latter a generic Java EE-container deploy plugin
I'd suggest to put your jar in the lib folder of the jboss server. This way, the jar is loaded in the shared classpath when the server starts. This will definitively serve the purpose.
Here is the jboss folder structured expleained.
http://docs.jboss.org/jbossas/guides/installguide/r1/en/html/dirs.html
I know this question has been marked as answered and the answer is that this currently is not possible, but I want to provide an alternative view. I am currently deploying Jboss modules to EAP 6.1 with Maven at my job. What we have done is use the maven-wagon plugin to scp the module to the tmp directory on the jboss server. I then use the maven-wagon plugin to issue a ssh command to the server to call the jboss-cli.sh script and tell it to perform a module installation. Here is a sample config:
<profile>
<id>uat</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>switchEnv</name>
<value>uat</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>wagon-maven-plugin</artifactId>
<version>1.0-beta-5</version>
<executions>
<execution>
<id>upload-file-qa-server-one</id>
<phase>deploy</phase>
<goals>
<goal>upload-single</goal>
</goals>
<configuration>
<fromFile>${project.build.directory}/${project.build.finalName}.${project.packaging}</fromFile>
<url>scp://jboss#jboss-server-1/tmp/</url>
<toFile>${project.name}.${project.packaging}</toFile>
</configuration>
</execution>
<execution>
<id>upload-file-qa-server-two</id>
<phase>deploy</phase>
<goals>
<goal>upload-single</goal>
</goals>
<configuration>
<fromFile>${project.build.directory}/${project.build.finalName}.${project.packaging}</fromFile>
<url>scp://jboss#jboss-server-2/tmp/</url>
<toFile>${project.name}.${project.packaging}</toFile>
</configuration>
</execution>
<execution>
<id>install-module-qa-server-one</id>
<phase>deploy</phase>
<goals>
<goal>sshexec</goal>
</goals>
<configuration>
<serverId>jboss-server-1</serverId>
<url>scp://jboss#jboss-server-1/tmp</url>
<commands>
<command>/opt/jboss/bin/jboss-cli.sh -c --command="module add --name=${project.name} --resources=/tmp/${project.name}.${project.packaging} --dependencies=javax.api,javax.transaction.api"</command>
<command>sleep 5</command>
<command>rm -f /tmp/${project.build.finalName}.${project.packaging}</command>
</commands>
</configuration>
</execution>
<execution>
<id>install-module-qa-server-two</id>
<phase>deploy</phase>
<goals>
<goal>sshexec</goal>
</goals>
<configuration>
<serverId>jboss-server-2</serverId>
<url>scp://jboss#jboss-server-2/tmp</url>
<commands>
<command>/opt/jboss/bin/jboss-cli.sh -c --command="module add --name=${project.name} --resources=/tmp/${project.name}.${project.packaging} --dependencies=javax.api,javax.transaction.api"</command>
<command>sleep 5</command>
<command>rm -f /tmp/${project.build.finalName}.${project.packaging}</command>
</commands>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
It´s not possible beause you have to use an OSGI approach.
To use maven try to work with OSGI within EAP, but it depends what you looking for. OSGI is supported since JBoss EAP 6.1.
If you are trying to work with EAI try to work with JBoss Fuse instead of EAP.
Then you will work with maven repositories, nexus or similar, hot deploy and all OSGI bundles stuff.

Having Maven2 copy resources to the build directory, but NOT bundle them in the JAR

I've started a new Maven project in NetBeans, accepting all the defaults. The POM, with all the JAR dependencies stripped out, is cut-n-pasted at the bottom of this question.
The application reads in various properties files (e.g. logging and config). It also reads in external resources such as fonts, images, and sounds. I do NOT want all these resources to be bundled up into the JAR file. Instead, I plan to deploy them in subdirectories beneath the directory where the JAR is deployed.
A simplified view of the project's directory structure looks like this:
-src
|---main
|---java
|---com.mypackage, etc
|---resources
|---conf
|---fonts
|---images
|---sounds
+target
What I would like to have after a clean build would look like this:
+src
-target
|---myproject-1.0.0.jar (compiled contents of "src/main/java" ONLY)
|---conf
|---fonts
|---images
|---sounds
However, when I do a "clean-and-build" or an "exec" through NetBeans (or the command-line for that matter)... what I'm actually getting looks like this:
+src
-target
|---classes
|---("src/main/java" and "src/main/resources" slammed together)
|---myproject-1.0.0.jar (the "classes" subdirectory JAR'ed up)
Can someone point me in the right direction for getting that first result rather than the second? I apologize if this is a silly question (I'm a Maven rookie), or if I overlooked a previously-asked duplicate. However, from the searching I've done on Stack Overflow... it looks like all the duplicate questions try to go the other way! (i.e. get resources into a JAR rather than keep them out)
pom.xml:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>steveperkins</groupId>
<artifactId>myproject</artifactId>
<packaging>jar</packaging>
<version>1.0.0</version>
<name>My Project</name>
<url>http://maven.apache.org</url>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.4</source>
<target>1.4</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
...
Although the proposed solutions would work they basically work around the maven conventions. A better alternative would be to filter out the resources so they are not included in the jar but still available as resources while working in the IDE. In the pom it should look like this:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<excludes>
<exclude>/conf/**</exclude>
<exclude>/fonts/**</exclude>
<exclude>/images/**</exclude>
<exclude>/sounds/**</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
This would effectively exclude them from the jar without any workarounds.
Here is the doc page for the jar plugin.
Though the above will answer your question may I suggest some additional possibility that could help you in your endeavour. As a second step, to still make these resources available you could package your project using the assembly plugin. this would allow you to create a zip file and place all the files, resources and jar, in an appropriate location so that when the zip is unpacked everything just falls into place.
If this project is part of a larger work you can still use the assembly plugin for each where you would have this situation and in the main project you could extract and reassemble them in a larger zip including all the necessary artifacts.
Lastly I suggest you leave the directory structure under target as-is. If you customize it it would be preferable to do it through the Maven variables so that the changes percolate to the other plugins. If you manually remove and rename stuff once Maven has gone through you may run into problems later. Normally the Maven jar plugin should be able to just get it right if you configure it the way you want so you have no needs to worry about what comes under target. Personally I use Eclipse and the pusign is pretty good at getting the IDE and Maven config in sync. For NetBeans I would suspect this would also be the case. If not the best approach would be to configure your project in NetBeans to use target/classes as a target folder for built artifacts and target/test-classes for stuff built from src/test/java.
Personally, I would not use the default location of resources but an "extra" location and configure the resources plugin to copy them where you want from there:
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<id>copy-resources</id>
<!-- here the phase you need -->
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target</outputDirectory>
<resources>
<resource>
<directory>src/non-packaged-resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
...
</build>
...
</project>
If you insist with using the default location (src/main/resources), I think you'll have to configure some exclusions (see below) to avoid resources getting copied by default and then use the same approach as above.
Another option would be to use the AntRun maven plugin and Ant to move files but this is not really the maven way so I won't detail it.
Resources
Copy Resources
Including and excluding files and directories
You can sonfigure a special execution of resources:copy-resources goal.
Eugene is on the right track but there's a better way to make this work.
It should look something like this:
<build>
<outputDirectory>target/${artifactId}-${version}</outputDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<classesDirectory>${project.build.outputDirectory}</classesDirectory>
<outputDirector>target</outputDirectory>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources/conf</directory>
<targetPath>../conf</targetPath>
</resource>
<resource>
<directory>src/main/resources/ANOTHER_PATH</directory>
<targetPath>../ANOTHER_PATH</targetPath>
</resource>
</resources>
</build>
You won't be able to get rid of the 'classes' directory, but you'll be able to give it a different name that shouldn't interfere with NetBeans.
You can find more about the <outputDirectory> element here.
You can find more about the jar plugin here.
You can find more about the <resource> element here.
As a side note, you may want to consider running Maven under a 1.6 JDK and fork the maven-compiler-plugin to use your 1.4 JDK for compiling. You can find out more about this here. That should give you a boost to your compile time. You can also tell surefire when running test cases to use the 1.4 JDK for execution as well.

Get sources of a snapshot dependency on Eclipse

Something bother me a lot...
On a big project with many dependencies, some of them are set as SNAPSHOT in Maven2.
The matter is that it seems i can't get the sources through Eclipse without loading the project or fixing the dependency to the last release.
For debugging, it's really annoying me...
EDIT
This is what i get in eclipse maven console:
26/08/10 11:31:46 CEST: Downloading http://repo-maven/archiva/repository/snapshots/com/blabla/1.1-SNAPSHOT/blabla-1.1-20100824.213711-80-javadoc.jar
26/08/10 11:31:47 CEST: Could not download sources for com.blabla:blabla:1.1-20100824.213711-80
On archiva i can see the deployed stuff i want to retrieve in eclipse...
Repository snapshots
Group ID com.blabla
Artifact ID blabla
Version 1.1-20100824.213711-80
Packaging jar
Parent com.blabla bla 1.1-SNAPSHOT (View)
Other Versions 1.1-20100824.213535-79
I can download sources of this artifact with my browser but not within Eclipse... Any idea?
The matter is that it seems I can't get the sources through Eclipse without loading the project or fixing the dependency to the last release. For debugging, it's really annoying me...
Well, these modules are probably not publishing source JARs as part of the "regular" build process (i.e. outside the release). If these modules are under your control (which is my understanding), configuring the Maven Source Plugin to produce source JARs for them and deploying them in your corporate repo should solve the problem. From the Usage page:
Installing the sources along with your artifact
There are two ways to do this. You can
either bind this plugin to a phase or
you can add it to a profile. The goals
source:jar-no-fork and
source:test-jar-no-fork are preferred
for binding the goal to the build
lifecycle.
Installing the sources using a phase binding
Here is how you would configure the
plugin in your pom.xml to run
automatically during the verify phase:
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
We are using the verify phase here
because it is the phase that comes
before the install phase, thus making
sure that the sources jar has been
created before the install takes
place.
Installing the sources using a profile
If you want to install a jar of your
sources along with your artifact
during the release process, you can
add this to your pom.xml file:
<project>
...
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
...
</project>
Using a profile would probably be a good idea so that building source JARs will only be done by the build running at the CI server level but not on developer machines.

Categories

Resources