Help with setting up classpath in an executable jar file - classpath

I am trying to build an executable jar with maven-assembly-plugin with all the dependencies. I want the dependencies in a /lib/ directory inside the jar, with the main jar outside, and the configuration files in the same level of the main jar.
My pom.xml is:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>org.main.Class</mainClass>
</manifest>
<manifestEntries>
<Class-Path>/ MainClass.jar</Class-Path>
</manifestEntries>
</archive>
<descriptors>
<!--Relative path to your descriptor -->
<descriptor>src/main/assembly/packagejar.xml</descriptor>
</descriptors>
</configuration>
</plugin>
The packagejar.xml is:
<id>eval</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>MainClass.jar</include>
</includes>
</fileSet>
</fileSets>
<files>
<file>
<source>/src/main/resource/logging.properties</source>
<outputDirectory>/</outputDirectory>
</file>
<file>
<source>/src/main/resource/log4j.properties</source>
<outputDirectory>/</outputDirectory>
</file>
<file>
<source>/src/main/resource/hibernate.cfg.xml</source>
<outputDirectory>/</outputDirectory>
</file>
</files>
<dependencySets>
<dependencySet>
<outputDirectory>/lib/</outputDirectory>
<useProjectArtifact>false</useProjectArtifact>
<unpack>false</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>
And the resulting manifest.mf file is:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: German
Build-Jdk: 1.6.0_22
Main-Class: org.main.Class
Class-Path: / MainClass.jar lib/dependency1.jar lib/dependency2.jar etc...
With this, I get the mainclass to execute, but it never finds the jars inside lib it needs to work. Probably I'm missing something basic. I've tried also adding in the pom.xml manifestEntries a lib/, lib/.jar, /lib and /lib/.
Any ideas?
Thanks in advance.

Refer Java Tutorial on why it can't be done in the way you expect. For your question on the way to release an executable jar, that is one possible way, but not always you might want to send dependencies separately. There are couple of plugins that will build your executable jar with the dependencies in it(but not the way as you expected). look into OneJAR and Maven Shade . One JAR builts an executable jar with the dependencies in a lib directory , but has custom class loader classes within the executable jar. Maven shade plugin unjars the dependency libraries within the executable jar. I used Maven Shade, because I had the necessity to do some transformations when building the executable along with spring dependencies.

Related

.jar missing in deployed JBoss .war

I know this has been asked a few times in the past, but I'm unable to find a solution (except for the "add the .jar to your project manually in Eclipse"..)
What I have:
A Maven project
A .jar web-service we've created (let's call it kc.ourwebservice)
After a clean install (in Eclipse or via the command line) and Full Publish in Eclipse (and yes, I have done an Update Maven Project - Force Update of Snapshots/Releases before that), this .jar can be found in:
This kc.ourwebservice.jar is present in our Nexus Repository Manager OSS
This kc.ourwebservice.jar is present in our Eclipse project at the Maven dependencies
This kc.ourwebservice.jar is present when I run mvn dependency:tree -Dverbose
This kc.ourwebservice.jar is present in my .m2 folder
However, it's missing from the deployed JBoss .war's lib folder, which is what my question is about.
I know I could manually add the .jar in Eclipse' Deployment Assembly (or org.eclipse.wst.common.component file), but every time I switch git branches or do an "Update Maven Project", it's gone again. And I also don't want to manually add this .jar when the project is put on a server.
I need a permanent solution so the .jar is correctly added to the deployed JBoss .war, using the Maven plugins that were designed for it.
One thing to add. This webservice has both an .aar and .jar. Both of them are necessary. The .jar when we're starting the application, so I gave it a <scope>compile</scope>, and all the .aar we use are only needed at runtime, so I gave it that scope (<scope>runtime</scope>).
Here is the relevant pom.xml code (lots of more dependencies, plugins and code at the ...'s, but those are irrelevant for this problem):
<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>
<parent>
...
</parent>
<artifactId>...</artifactId>
<packaging>war</packaging>
...
<properties>
...
<ourwebservice.version>1.0.0</ourwebservice.version>
...
</properties>
...
<plugins>
...
<!-- Takes care of copying the aar services to the WEB-INF/services -->
<plugin>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-repo-maven-plugin</artifactId>
<version>1.7.3</version>
<configuration>
<outputDirectory>${project.build.directory}/generated-resources</outputDirectory>
<stripServiceVersion>false</stripServiceVersion>
<services>...,ourwebservice</services>
</configuration>
<executions>
<execution>
<phase>generate-resources</phase>
<id>deploy webservices</id>
<goals>
<goal>create-repository</goal>
</goals>
</execution>
</executions>
</plugin>
...
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>${maven.war.plugin.version}</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<outputDirectory>${warOutputDir}</outputDirectory>
<webappDirectory>${webappDirectory}</webappDirectory>
<warName>${project.artifactId}</warName>
<!-- Tell the maven war plugin to use the merged web.xml -->
<webXml>${warOutputDir}/web.xml</webXml>
<warSourceExcludes>.gwt-tmp/**</warSourceExcludes>
<webResources>
<resource>
<directory>${basedir}/src</directory>
<targetPath>WEB-INF/classes</targetPath>
<excludes>
<exclude>**/*.java</exclude>
<exclude>sample-properties.properties</exclude>
<exclude>sample-log4j.properties</exclude>
</excludes>
</resource>
<!-- Copy the generated services that were extracted from the dependencies to the WEB-INF/services folder of the war archive. -->
<resource>
<directory>${project.build.directory}/generated-resources/services</directory>
<targetPath>/WEB-INF/services</targetPath>
<includes>
<include>**/*.aar</include>
</includes>
</resource>
...
</webResources>
<!-- The axis2 services should not be stored in the WEB-INF/lib -->
<packagingExcludes>WEB-INF/lib/*.aar</packagingExcludes>
</configuration>
</plugin>
<!-- JBoss plugin used to deploy war file - http://mojo.codehaus.org/jboss-maven-plugin/ -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jboss-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<hostName>${deploymentHostName}</hostName>
<port>${deploymentPort}</port>
<fileName>${deploymentFileName}</fileName>
<serverName>default</serverName>
<jbossHome>
//${deploymentHostName}/${jbossHome}
</jbossHome>
</configuration>
</plugin>
</plugins>
...
<dependencies>
...
<dependency>
<groupId>kc</groupId>
<artifactId>ourwebservice</artifactId>
<version>${ourwebservice.version}</version>
<type>aar</type>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>kc</groupId>
<artifactId>ourwebservice</artifactId>
<version>${ourwebservice.version}</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
...
</dependencies>
...
</project>
Does anyone has any idea why the .jar isn't deployed to the .war? Or better yet, does anyone know a solution so the .jar is always deployed to this .war when doing a clean install and publish?
All other .jar files are present in the .war, this webservice is the only one missing.

Dependencies from pom.xml not considered by Eclipse in Tycho Project

I created a Tycho project with an eclipse-plugin packaging. The project includes some dependencies that are specified via pom.xml. The relevant pom sections are:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<tycho.version>0.15.0</tycho.version>
</properties>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-maven-plugin</artifactId>
<version>${tycho.version}</version>
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>target-platform-configuration</artifactId>
<version>${tycho.version}</version>
<configuration>
<pomDependencies>consider</pomDependencies>
<environments>
<environment>
<os>win32</os>
<ws>win32</ws>
<arch>x86</arch>
</environment>
<environment>
<os>linux</os>
<ws>gtk</ws>
<arch>x86_64</arch>
</environment>
<environment>
<os>macosx</os>
<ws>cocoa</ws>
<arch>x86_64</arch>
</environment>
</environments>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>juno</id>
<layout>p2</layout>
<url>http://download.eclipse.org/releases/juno</url>
</repository>
<repository>
<id>com.springsource.repository.bundles.release</id>
<name>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases</name>
<url>http://repository.springsource.com/maven/bundles/release</url>
</repository>
<repository>
<id>com.springsource.repository.bundles.external</id>
<name>SpringSource Enterprise Bundle Repository - External Bundle Releases</name>
<url>http://repository.springsource.com/maven/bundles/external</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>com.springsource.org.testng</artifactId>
<version>6.4.0</version>
</dependency>
<dependency>
<groupId>com.google.guice</groupId>
<artifactId>com.springsource.com.google.inject</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.aopalliance</groupId>
<artifactId>com.springsource.org.aopalliance</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
And the Manifest is:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Plugin-project-pure
Bundle-SymbolicName: plugin-project-pure
Bundle-Version: 1.0.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: org.eclipse.equinox.app,
org.eclipse.uml2.uml;bundle-version="4.0.0",
org.eclipse.uml2.uml.resources;bundle-version="4.0.0",
org.junit;bundle-version="4.10.0",
com.springsource.org.testng;bundle-version="[6.4.0,6.4.0]"
The project only consists of a class in the default package that uses an annotation from org.testng.annotations to test that during compilation the dependency is included.
If I'm building the project on the command line with Maven 3.0.4 everything works fine. After importing the project in Eclipse Juno, I get multiple errors. The most important one is in the manifest and it states that the bundle com.springsource.org.testng can't be resolved. There is also a compile error in the class, because the import of the annotation is not possible. The project has the Maven Nature configured. Am I missing something so that Eclipse Juno will also consider the dependencies of the pom?
You can circumvent this problem splitting your project build into two parts:
First, aggregate your POM dependencies into a p2 repository. You'll need an eclipse-feature and an eclipse-repository module for this, plus a separate parent POM that lists the POM dependencies and configures pomDependencies=consider.
In the second build, add the p2 repository from the first build to the target platform, e.g. via a jar:file: URL pointing to the build result in your local Maven repository.
Then, you can also configure your target platform in Eclipse to include the p2 repository from the first build (which depends on how you currently configure it). You'll get the best consistency between Tycho and Eclipse if you use a so-called target definition file, which you can use both as target platform in Eclipse and in Tycho.
I am aware that all this is quite a bit of effort to set up, but AFAIK there are no better solutions that fully work.
The most elegant solution to all problems that exist between maven-RCP problems is to use the
p2-maven-plugin. Here is the brief summary of those problems (cuts from the link above):
In order to add a third-party dependency to an Eclipse RCP project the
dependency has to reside in a P2 update site.
Eclipse (and other providers) provide a set of public update sites,
but obviously not all popular and publicly available dependencies are
there (that is the problem number #1).
Since Eclipse RCP is an OSGi environment in order to add a dependency
to a p2 update site the depenedncy has to be an OSGi bundle (that is
the problem number #2).
So, let’s sum up for now: all our artifacts have to be OSGi bundles,
but they are not always bundles and they have to be located in a P2
site, but we do not have that site. How do we proceed then?
It is not that difficult, there is a ‘bnd’ tool written by Peter
Kriens that can transform your jars into bundles. There is also a
convenience tool provided by Eclipse RCP that can generate a P2 site
(in a cumbersome and painful way though). Both tools assume that all
your jars/bundles are located in a local folder - which means that you
have to download them by-hand. You could use Maven to automate it a
bit, but there is a significant difference in the way how Maven
calculates a dependency tree and this is not alwyas compatible with
the OSGi way (that is the problem number #3). Let us elaborate on it a
bit more.
It allows you to define a pom-packaged project that will resolve all maven dependencies, convert all non-OSGi ones to bundles and generate a p2 site from them.
Below is the full minimal pom file including the dependency on slf4j-log4j12 (which implicitly depends on both slf4j and log4j v1.2):
<?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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.berezovskiy.project</groupId>
<artifactId>p2</artifactId>
<packaging>pom</packaging>
<version>1.0.0</version>
<build>
<plugins>
<plugin>
<groupId>org.reficio</groupId>
<artifactId>p2-maven-plugin</artifactId>
<version>1.1.1-SNAPSHOT</version>
<executions>
<execution>
<id>default-cli</id>
<configuration>
<artifacts>
<artifact>
<id>org.slf4j:slf4j-log4j12:1.7.7</id>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.12.v20130726</version>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
<webAppSourceDirectory>${basedir}/target/repository/</webAppSourceDirectory>
<webApp>
<contextPath>/site</contextPath>
</webApp>
</configuration>
</plugin>
</plugins>
</build>
<pluginRepositories>
<pluginRepository>
<id>reficio</id>
<url>http://repo.reficio.org/maven/</url>
</pluginRepository>
</pluginRepositories>
</project>
P.S. I usually do not post answers to old and answered questions, but in my case it took so long to resolve this issue in a clean and elegant way that I decided to write about it. Additionally, the solution has appeared in late 2013.
from the command line navigate to the folder where the pom.xml is located.
Run mvn eclipse:eclipse.
This should build a valid eclipse project.

Deploying a War File to Tomcat Root With Maven pom.xml

Assuming the following pom.xml maven would build a client.war file which when deployed to Tomcat will have the URL www.server.com:8080/client/
What would one have to change so the application can be reached at the server root www.server.com:8080/?
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>...</groupId>
<artifactId>client</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>...</name>
<url>http://maven.apache.org</url>
<build>
<resources>
<resource>
<directory>target/generated-resources</directory>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
...
</plugins>
<finalName>client</finalName>
</build>
...
</project>
I believe you can leave the war named client.war if you'd like. Then configure the tomcat6 plugin, setting the path like this:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat6-maven-plugin</artifactId>
<version>2.0-beta-1</version>
<!-- put the configuration in an execution if you want to... -->
<configuration>
<path>/</path>
<warFile>${project.build.directory}/client.war</warFile>
<!-- other config options here -->
</configuration>
</plugin>
I haven't used tomcat7 version of the plugin, but I'm guessing it's similar.
Since you're using the combination of eclipse, tomcat, and maven, I'm going to make the guess that the m2e-wtp plugin is in use here. There's a FAQ that addresses this. This also shows though how to change your context root in a maven specific way (using the war plugin for specifying a finalName for the war) which results in a correctly named war file (such as ROOT.war as mentioned in other answers.
Maven war plugin (which is defined on super-pom by default) will only generate a war file. It's up to you to set up your app on Tomcat. If you want to add the "deploy to a container" to your maven build, go with Tomcat Maven Plugin or Cargo Maven Plugin.
What you want has nothing to do with Maven, actually. Setting your war name to ROOT.war should do it (<finalName>ROOT</finalName> on your build section), but if you want to add your context.xml to the war file, you could do something like (assuming src/main/webapp is your webapp folder defined by maven):
`<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webResources>
<webResource>
<directory>${basedir}/src/main/webapp/META-INF</directory>
<includes>
<include>context.xml</include>
</includes>
<targetPath>META-INF</targetPath>
<filtering>true</filtering>
</webResource>
</webResources>
</configuration>
</plugin>
`

How to debug an OSGi Bundle inside eclipse using maven structured project

I have a maven project which library should also be an OSGi bundle with an
declarative service. I added the OSGI-INF folder with the service.xml inside
src/java/resources which will be added to the jar. But: When I start the project as equinox project, where I want to check if the service is loaded, I get the error that the OSGI-INF/service.xml can't be found. I guess eclipse won't add the resources folder to the classpath when starting.
BTW: The MANIFEST-MF is in the root folder and the pom.xml contains the following text:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
Has anbody a good idea how to tell eclipse where to find the metadata files? I'm using m2eclipse if this is relevant.
Thanks in advance
Hannes
I've the same issues but I've manually tweaked my POM.xml for copying the generate target/classes/META-INF/** stuff (MANIFEST.MF, property files, spring XMLs, ...) into the project ROOT folder (which Eclipse PDE expects):
<!--
We copy all stuff from target/classes/META-INF into META-INF/ in order
to keep Maven output with PDE.
-->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<id>synch-pde-metadata-from-maven</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/META-INF</outputDirectory>
<resources>
<resource>
<directory>target/classes/META-INF</directory>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<!--
We delete all stuff from the root bundle's META-INF
-->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<filesets>
<fileset>
<directory>META-INF</directory>
<includes>
<include>**/*</include>
</includes>
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
</configuration>
</plugin>
(I also clean up things when mvn clean is called) It is not really efficient but it works.
Ps: you may have to right-click on the project and make it a plug-in project in order for this to work.
The Problem is that Eclipse needs that OSGI-INF (and also META-INF) Folder in root.
I have found a link on how to probably solve the problem.
https://www.nuxeo.com/blog/working-with-osgi-and-maven-in-eclipse/
Basically they put the OSGI-INF and META-INF Folders into src/main/resources
Then they set the src/main/resources Folder as root of the OSGI project. So that Eclipse has both Folders at root.
To have Soure Files also available they added a Linked Resources to src/main/java by adding an entry to the .project File
<linkedResources>
<link>
<name>src</name>
<type>2</type>
<locationURI>PARENT-1-PROJECT_LOC/java</locationURI>
</link>
</linkedResources>
Now you just need to copy the .prject and .classpath Files into src/main/resources (your new root) and everything should be working.
By the time of this writing i didn't test this on my own but will do so in the near future.

Building jar with maven-scala-plugin

I created scala application and now I want to build jar.
I run mvn package than I try to run jar by command
java -jar target/burner-1.0-SNAPSHOT.jar
and I see error:
Failed to load Main-Class manifest attribute from
How can I define Main-Class property?
Do I need to create Manifest.mf? where?
Or I need to have mainclass property somewhere in pom.xml?
Update:
I have created src/main/resources/MANIFEST.MF file with contents
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: itsabear
Main-Class: ru.dmteam.App
Build-Jdk: 1.6.0_20
I did not forget line ending at the end of file.
after mvn package I see new jar. I checked manifest.mf in this jar - it contains right main-class but when I type java -jar target/burner-1.0-SNAPSHOT.jar I still see an error Failed to load Main-Class manifest attribute from
My pom.xml http://pastie.org/1070483
UPDATE 2
I discovered that now there are two manifest.mf files in the jar.
MANIFEST.MF and META-INF/MANIFEST.MF
I moved my custom MANIFEST.MF to just created META-INF folder(in src/main/resources) but now mvn package overrides it while creating jar...
After creating a new maven project using the scala-archetype-simple archetype (A simple project that prints 'Hello World'), I needed to add the following to my pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>test.App</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
for the class test.App to run as desired when invoked with the command
java -jar ./target/mytest-1.0-SNAPSHOT-jar-with-dependencies.jar
After running the command
mvn package
you can run the jar this way
scala -cp target/projectname-1.0-SNAPSHOT.jar