Spring Boot Maven - Include native library - spring

In my project i'm using Sigar library that require some native library. I would like to include all the files (.ddl, .so etc - that are platform specific) inside the JAR or, in the same directory where the jar will be run.
Sigar search those library in the java.library path, but i cant include all of them in the system PATH (my application will be executed in some production machines, and i can't touch the PATH).
In order to do this, i've this build phase in my pom.xml
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkMode>once</forkMode>
<workingDirectory>target</workingDirectory>
<argLine>-Djava.library.path=${baseDir}/src/main/resources/lib</argLine>
</configuration>
</plugin>
</plugins>
</build>
When i run the pack goal (that is included in spring-boot-maven-plugin) and i run the jar (with java -jar myJar.jar) i got this error:
Unable to open nested entry 'lib/libsigar-amd64-freebsd-6.so'. It has
been compressed and nested jar files must be stored without
compression. Please check the mechanism used to create your executable
jar file
Someone can tell me how i can build this JAR ? I've just used spring-boot-maven-plugin because is included in Spring Boot Starter project.

Related

Springboot executable jar error using java -jar

using command /opt/jdk1.8.0_211/bin/java -jar webprx.jar get this error: Error: Invalid or corrupt jarfile webprx.jar
jar was build with mvn clean package and mvn install
Pom
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>
<packaging>jar</packaging>
Remove the executable configuration.
From the documentation this makes it executable by *NIX systems.
Make a fully executable jar for *nix machines by prepending a launch script to the jar.
Currently, some tools do not accept this format so you may not always
be able to use this technique. For example, jar -xf may silently fail
to extract a jar or war that has been made fully-executable. It is
recommended that you only enable this option if you intend to execute
it directly, rather than running it with java -jar or deploying it to
a servlet container.
https://docs.spring.io/spring-boot/docs/2.1.5.RELEASE/maven-plugin/repackage-mojo.html

Spring Boot useTestClasspath throws CannotLoadBeanClassException and ClassNotFoundException

I have a maven project with a test class located at src/test/java/MyDevClass which is intended for development/testing purposes only. I would like to use it when I start spring-boot-maven-plugin with the command line mvn spring-boot:run.
So, my pom.xml contains:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- TODO: Will create a maven profile and have useTestClasspath only for development/testing -->
<useTestClasspath>true</useTestClasspath>
</configuration>
</plugin>
</plugins>
</build>
But, I get the following error:
org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [MyDevClass]
Caused by: java.lang.ClassNotFoundException: MyDevClass
Intriguing enough, I have another project using tomcat7-maven-plugin and it works fine:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.0</version>
<configuration>
<useTestClasspath>true</useTestClasspath>
</configuration>
</plugin>
What I am missing?
Spring-boot maven plugin does not include current module's test sources (and resources) into classpath even if useTestClasspath is set to true.
I ran a forked execution with verbose logging (-X flag to Maven), and the plugin listed the forked JVM classpath. Test classes were not included.
If you look at the plugin sources (version 1.5.3 at time of writing), the flag useTestClasspath is only used in the addDependencies method.
I see two options as workarounds
Add the target/test-classes dir to the run classpath:
<directories>
<directory>${project.build.testOutputDirectory}</directory>
</directories>
For older plugin version use:
<folders>
<folder>${project.build.testOutputDirectory}</folder>
</folders>
The problem here is that the folder is added to the beginning of classpath, while test files are preferable at its end.
Create another Maven module with test classes and resources, and add it as a <scope>test</scope> dependency.

IntelliJ: Copy war file after build

I'm using IntelliJ + Maven to generate war files.
The war is always generated in ProjectDirectory/target/projectname-version.war
After the build process is done, I want to copy the generated war file into a different location (something like cp output X:/remote/tomcat_webapps/projectname.war).
I already tried to configure the directory where maven builds the project (within the pom.xml). However, maven always deletes the containing folder and all its contents, so that is not an option.
How can I automatically copy the generated war file into a different location?
you can modify the maven war plugin in your pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<outputDirectory>X:/remote/tomcat_webapps</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
I'm not quite sure, if it is the outputDirectory or should it be webappDirectory, like in the documentation
https://maven.apache.org/plugins/maven-war-plugin/usage.html

spring boot loading jars (application dependencies and external file system jars)

I am trying to figure out what is the best way to setup a spring boot application in such a way that its has its own jar dependencies but additional jars are added to classpath at runtime when its being run as java -jar command. What approach makes more sense
Use the original jar (without dependencies added to it) and place all jars (application and runtime) in a folder on file system and use PropertiesLauncher to specify the loader.path to jars folder.
Use the fat jar (with application jars) place the additional jars on the filesystem and somehow include those as additional jars that need to be added to classpath. Not sure how this can be done.
Is there another better way to do this
The PropertiesLauncher was designed to work with fat jars, so you should be able to keep the fat jar and add as many additional dependencies as you like in an external location, e.g. with loader.path=/opt/app/lib:lib. I guess that's your option 2? If it doesn't work we can discuss in a github issue.
I resolved this issue using the following spring-boot-maven-plugin configuration, I had to build my Uber jar without excluded artifacts to create my external "lib" directory, then I added my excluded artifacts again and packaged my Uber jar with my application specific dependencies only.
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.3.1.RELEASE</version>
<configuration>
<layout>ZIP</layout>
<executable>true</executable>
<excludeArtifactIds>
<!-- My libs which will be packaged with my Uber jar-->
<!-- core,data-feeder,engine,lightspeed-tcp-api,order-manager,store,strategies,utils,viewer -->
<!-- Other libs -->
antlr,aopalliance,aspectjrt,aspectjweaver,classmate,commons-lang,
dom4j,h2,hibernate-commons-annotations,hibernate-core,hibernate-entitymanager,
hibernate-jpa-2.1-api,hibernate-validator,jackson-annotations,jackson-core,jackson-databind,
jandex,javassist,javax.transaction-api,jboss-logging,jboss-logging-annotations,jcl-over-slf4j,
jul-to-slf4j,log4j-over-slf4j,logback-classic,logback-core,mysql-connector-java,slf4j-api,
snakeyaml,spring-aop,spring-aspects,spring-beans,spring-boot,spring-boot-autoconfigure,
spring-boot-starter,spring-boot-starter-aop,spring-boot-starter-data-jpa,spring-boot-starter-jdbc,
spring-boot-starter-logging,spring-boot-starter-tomcat,spring-boot-starter-web,
spring-boot-starter-websocket,spring-context,spring-core,spring-data-commons,spring-data-jpa,
spring-expression,spring-jdbc,spring-messaging,spring-orm,spring-tx,spring-web,spring-webmvc,
spring-websocket,tomcat-embed-core,tomcat-embed-el,tomcat-embed-logging-juli,tomcat-embed-websocket,
tomcat-jdbc,tomcat-juli,validation-api,xml-apis
</excludeArtifactIds>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
Then, I added the following property to my "application.properties" which inside my jar "resources/" dir to specify my "lib" dir for Spring PropertiesLauncher where I put "lib" dir along with my jar in the same dir.
loader.path=lib/
Finally, I did run my jar using the following command
java -jar back-tester-0.0.1-beta-01.jar
Also, you can add the "loader.path" property to your command line without putting it in your "application.properties" like the following command but this way didn't work with me as I packaged my jar as an executable one which I'm running as linux service.
java -Dloader.path="lib/" -jar back-tester-0.0.1-beta-01.jar
Now, I successfully reduced my jar size from 29 M to only 1 M jar which contains only my application specific libs and it works out of the box.
thank you #Ashraf Sarhan, you rescue my two days :)
I added in pom file:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layout>ZIP</layout>
<executable>true</executable>
<mainClass>vn.com.Mymainclass</mainClass>
<excludes>
<exclude>
<groupId>com.vn.groupId</groupId>
<artifactId>excluded-id-a</artifactId>
</exclude>
<exclude>
<groupId>com.vn.groupId</groupId>
<artifactId>excluded-id-b</artifactId>
</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
And Placed ./lib folder containing two jars of two files which excluded above beside with my-main-spring-boot-app.jar file, and I ran:
java -Dloader.path="lib/" -jar my-main-spring-boot-app.jar
It worked perfectly.

How to include resources from war to another maven project

I have a maven project , which needs to copy webapp/WEB-INF/ resources from another maven project which is packaged as a war .
How do I do it ?
PLease suggest
As Bittrance said, you should use the maven dependency plugin.
The better way is to create project that include all your shared resources, probably a type zip, which is build up with the assembly plugin. This is the good "maven way". It's a better solution than unpacking a war.
Then, refer it
<dependency>
<groupId>com.mygroup/groupId>
<artifactId>my-dependencies</artifactId>
<version>1.0.0</version>
<type>zip</type>
</dependency>
Next, you use the maven dependency plugin to unpack your resources, in the directory of your choice (probably WEB-INF/ ?)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-cfg-test-resources</id>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<phase>resources</phase>
<configuration>
<outputDirectory>${project.build.directory}/WEB-INF/</outputDirectory>
<includeArtifacIds>my-resources</includeArtifacIds>
<excludeTypes>pom</excludeTypes>
<excludeTransitive>true</excludeTransitive>
</configuration>
</execution>
</executions>
</plugin>
I'm not realy sure of this code snippet (written for another purpose), but this is an example.
For more information, please follow this link : http://maven.apache.org/plugins/maven-dependency-plugin/
If you can't shared a common-project including your files, you can unpack war including only ftl (or whatever you want), but it's not a realy clean solution ;)
There is a lot of posts that deal with this subject :
Unzip dependency in maven
...
Just try with the keywords maven-dependency-plugin, unpack :)
Hope that will help you.
I can see some alternatives:
Use external references in your version control system to point all repos to the same files.
The Maven Dependency module can copy and unpack project dependencies. From there, you can use the Maven Assembly plugin (or Ant targets) to include parts of that dependency in your own installation.
At least for the FTL files, perhaps you could package them in a separate Jar file and then load them as resources through the class loader.
If the resources are filtered, you may get into problem with solution 1 if you want the filtered version and 2, 3 if you want the source version.
Hope this helps.
(This assumes your dependent project is java (jar) and not another web app, if it is a webapp I think the solution is similar).
I suggest a (slightly) different approach:
Instead of reading resources from war, add this to your war pom, to generate a jar in the artifact as well as a war:
<!-- maven war plugin config -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<configuration>
...
<attachClasses>true</attachClasses>
<classesClassifier>some-string</classesClassifier>
</configuration>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
</plugin>
...
<resources>
<!-- This is for inclusion in the jar, so dependent module can load it -->
<resource>
<targetPath>some-path</targetPath>
<directory>src/main/webapp/path...</directory>
<includes>
<include>your-resource</include>
</includes>
</resource>
</resources>
And this to your consuming pom, so the generated jar will be loaded:
<dependency>
<groupId>com.company</groupId>
<artifactId>...</artifactId>
<classifier>some-string</classifier>
</dependency>
Then you will be able to load the resources the usual way (getResourceAsStream("some-path/your-resource"))

Resources