I am having a problem with maven. I have included a dependency as such in my pom.xml:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.6</version>
</dependency>
I am using Intellij as an IDE, and I get no compile warnings there or anything. I am using the command line to run the maven commands, and I can run mvn install compile package all without trouble.
However, when I try running the jar as such:
java -cp target/stride-1.0-SNAPSHOT.jar com.myapp.maven.App
I get this error:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/csv/CSVFormat
at com.stride.maven.App.parseCsv(App.java:43)
at com.stride.maven.App.main(App.java:25)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.csv.CSVFormat
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
Clearly, maven cannot find that path. I tried deleting the .m2, rebuilding, and mostly everything I have found on stackoverflow, but I cannot find the issue, or get visibility into the issue. Note, in my Intellij I can see the dependency in the external libraries.
I have also tried using shade to copy the dependancies to the jar:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<transformers>
<transformer implementation=
"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.myapp.maven.App</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
Following which I reran mvn clean install package and then my build command. No luck.
I have also tried Maven Assembly plugin. Guess what, no luck!
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>
com.myapp.maven.App
</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
I confirmed the dependencies are not even getting built in.
Thanks!
Maven works great in this case.
However, you seem to miss the point of dependency.
When you define a dependency maven uses it during the compilation (hence no errors in both intelliJ and when you execute mvn install)
But this doesn't mean that dependency is placed right into the jar.
There are more complicated packaging types of application where it indeed works like this (dependant jars are included into the artifact) for example Spring boot application, Web Archives (WAR) and so forth. But since you compile a regular JAR it will include only the classes of your module and won't include classes of commons-csv in this case.
So in order to be able to run this application you should chose one of:
Put Jar of commons-csv (as well as other dependencies that you might have) into class path: java -classpath <path-to-commons-csv> -jar YourApp
Use Maven Shade Plugin to create a jar that will indeed include all the dependencies as classes
As mentioned in the other answers, you need to package up your dependencies in your executable jar (a.k.a. Uber-JAR). You mention you have tried two ways: using the Maven assembly with a descriptorRef jar-with-dependencies and the Maven shade plugin.
First global remark: Maven plugin configuration can be defined in a <pluginManagement> block or directly in the <build> part of a POM. I would suggest to put them in the <build>, and I assume you already put them there, but I can't verify that since you only pasted a part of it in your question.
When using the jar-with-dependencies descriptorRef in the Maven assembly plugin, two jar files will be created in your target/ folder: stride-1.0-SNAPSHOT.jar and stride-1.0-SNAPSHOT-with-dependencies.jar. You should use the -with-dependencies.jar, so run java -cp target/stride-1.0-SNAPSHOT-with-dependencies.jar com.myapp.maven.App
The Shade plugin offers more options than the Maven assembly plugin. However in the code you pasted you have not bound the execution of the Maven Shade plugin to the package phase of Maven's lifecycle. If you run a mvn package you will NOT see the Maven shade plugin as part of the build steps that Maven did. If you look more closely to mkyongs guide, you'll see that you need to include a <phase>package</phase> in your <execution> block.
Hi the problem is that when the jar is getting created the dependencies being downloaded is not being attached to the executable jar that is why there error is showing up we can add the below section in the build tag to get the dependencies attached to the executable jar and then you can execute the jar with java -jar command
maven-assembly-plugin
package single
... wow.dxdatagenerator.App
jar-with-dependencies
-->
Related
I'm trying to deploy my first java application using Maven. In this case, this is just a simply telegram bot, but I get this error when trying to run it locally. After a little investigation, I found that java.lang.NoClassDefFoundError is an error that occurs when a jar file is not able to access a specific class in runtime, and in order to solve this, is necessary to add that class on classpath.
I understand that when working on Maven, there is a simple way to add classes on the classpath, and it's by adding the right dependency on the pom.xml file.
So this is what i've added:
<dependencies>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-abilities</artifactId>
<version>5.0.1.1</version>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>5.0.1</version>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-meta</artifactId>
<version>5.0.1.1</version>
</dependency>
</dependencies>
And I think it was successfully added on the classpath because this is what I get when I read the MANIFEST.MF file on my jar file:
Manifest-Version: 1.0
Created-By: Apache Maven 3.6.3
Built-By: agujared
Build-Jdk: 15.0.1
Class-Path: telegrambots-abilities-5.0.1.1.jar commons-lang3-3.11.jar ma
pdb-3.0.8.jar kotlin-stdlib-1.2.71.jar kotlin-stdlib-common-1.2.71.jar
annotations-13.0.jar eclipse-collections-api-11.0.0.M1.jar eclipse-coll
ections-11.0.0.M1.jar eclipse-collections-forkjoin-11.0.0.M1.jar lz4-1.
3.0.jar elsa-3.0.0-M5.jar slf4j-api-1.7.30.jar telegrambots-5.0.1.jar j
ackson-annotations-2.11.3.jar jackson-jaxrs-json-provider-2.11.3.jar ja
ckson-jaxrs-base-2.11.3.jar jackson-module-jaxb-annotations-2.11.3.jar
jackson-core-2.11.3.jar jakarta.xml.bind-api-2.3.2.jar jakarta.activati
on-api-1.2.1.jar jackson-databind-2.11.3.jar jersey-hk2-2.32.jar jersey
-common-2.32.jar osgi-resource-locator-1.0.3.jar jakarta.activation-1.2
.2.jar hk2-locator-2.6.1.jar aopalliance-repackaged-2.6.1.jar hk2-api-2
.6.1.jar hk2-utils-2.6.1.jar javassist-3.25.0-GA.jar jersey-media-json-
jackson-2.32.jar jersey-entity-filtering-2.32.jar jersey-container-griz
zly2-http-2.32.jar jakarta.inject-2.6.1.jar grizzly-http-server-2.4.4.j
ar grizzly-http-2.4.4.jar grizzly-framework-2.4.4.jar jakarta.ws.rs-api
-2.1.6.jar jersey-server-2.32.jar jersey-client-2.32.jar jersey-media-j
axb-2.32.jar jakarta.annotation-api-1.3.5.jar jakarta.validation-api-2.
0.2.jar json-20180813.jar httpclient-4.5.13.jar httpcore-4.4.13.jar com
mons-logging-1.2.jar commons-codec-1.11.jar httpmime-4.5.13.jar commons
-io-2.8.0.jar telegrambots-meta-5.0.1.1.jar guava-30.0-jre.jar failurea
ccess-1.0.1.jar listenablefuture-9999.0-empty-to-avoid-conflict-with-gu
ava.jar jsr305-3.0.2.jar checker-qual-3.5.0.jar error_prone_annotations
-2.3.4.jar j2objc-annotations-1.3.jar
Main-Class: domain.Main
As you can see, telegrambots-meta-5.0.1.1.jar is part of the classpath attribute.
How can I solve this?
By the way, I'm using Heroku Cloud to deploy this
Sounds like you want and need to create a runnable/ executable JAR file (with external dependencies).
This requires your build process to be enhanced by this step, regardless of where it is executed Heroku, Jenkins, Bamboo or on your local - this is a maven setting and will affect each of them.
Also on your local you can run the build of your project by executing mvn clean package in your IDE and afterwards to run the created JAR from the target folder with: java -jar ${yourJarName}. It'll likely fail for the same reason.
This is, because Maven dependencies are added with a so called scope. These are for example:
compile
provided
runtime
test
Whereby compile is the default one and being implicitly applied in case you don't specify it - like in your case. (You can read more about the scopes here)
This means Maven will add your dependency to your IDE at compile time, but it will be missing at the runtime, when your trying to execute it.
The solution is to create a runnable/ executable JAR file (also called *fat JAR *) containing all the needed dependencies.
You can do it directly within Maven with the help of the maven-assembly-plugin like so:
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
Then you need to build your JAR like:
mvn clean compile assembly:single
Note: The compile goal must be added before assembly:single or otherwise the code on your own project is not included.
To ease the handling of the process this goal commonly is tied to a Maven build phase to execute automatically. This ensures the JAR is built when executing mvn clean package, mvn clean install or performing a deployment/ release:
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Like this you can simply build your project with the mvn clean package command (probably the most common one) and it'll include the creation of the runnable/ executable JAR file. This will include all your needed dependencies and should resolve your java.lang.NoClassDefFoundError issue.
Just a short additional note
Creating runnable/ executable JAR file respectively fat JAR is not the only solution and maybe in some contexts unwanted. Since fat JAR files include all their needed dependencies, they are fairly big with all the related drawbacks (requires more bandwith to transmit, download size increases, same dependencies might be carried in multiple different JARs, ...).
For this reasons the fat JAR creation is avoided in Web Application Development with Java EE. Dependencies are only added at compile time, since it is known that a Servlet Container or Application Container like Tomcat or Wildfly will provide these at runtime to avoid the java.lang.NoClassDefFoundError. Therefore the different applications (JARs or in this context called WARs) don't need to provide the dependencies themself.
In your case it might also be the solution that you'll still build the thin JAR, but will provide the needed dependencies at runtime (e.g. separately downloading it and then specifying in the classpath before the execution).
So i have a following problem:
I have a maven-project with several maven-dependencies. When i run mvn install it'll be packaged as .jar and the .jar together with the .pom-File will be placed inside my maven-repository. Now, this .jar does not contain other dependencies (and is also not supposed to!). Now, given that i have all the dependencies needed installed in my maven repository (which obviously maven will take care of), how can i run this jar on the command line without setting the classpath to point to every damn jar in the maven-repository? Is there any other way? mvn exec:java only seems to work within the maven-source directory, where it looks for the "pom.xml". But after installing, "pom.xml" becomes "name-version.pom" and i have a .jar instead of direct source/class-files. Is there any other way to point mvn exec:java to work with the .jar and .pom-File within the maven repository? Or maybe some other and better approach to do so?
Thanks in advance :)
EDIT1: I'll just put my comment from below in here to avoid further misunderstandings:
I do not want to put the dependency jars somewhere. I want to use the repository maven already takes care of.Theoretically given, that i have ALL libraries i will ever need already in my local maven repository. I want to be able to download any other maven project, that might be using some of the libraries i already have installed in my local repository, also install it using "maven install", then remove the source i downloaded and then execute the .jar created by maven and tell java or maven (depending on what the best approach is) to look for the dependencies of that project in my local maven repository.
I hope i made it clear enough :)
EDIT 2: So i decided to use mvn install to install the projects into my local .m2 repo and also keep the projects unpackaged in some defined folder.Then i can just call mvn exec:java inside those projects to run them and maven will resolve all the dependencies for me.
You may exclude some dependency that you don't want to be in your project like this -
<project>
...
<dependencies>
<dependency>
<groupId>sample.ProjectA</groupId>
<artifactId>Project-A</artifactId>
<version>1.0</version>
<scope>compile</scope>
<exclusions>
<exclusion> <!-- declare the exclusion here -->
<groupId>sample.ProjectB</groupId>
<artifactId>Project-B</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
For more information you may check the link
Make a Jar executable and define classpath dependencies with maven can be done using maven-jar-plugin to create a manifest file. The manifest file is usually used for that
example
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<!-- It define the classpath dependencies -->
<addClasspath>true</addClasspath>
<classpathPrefix>dependency-jars/</classpathPrefix>
<!-- it makes the jar executable -->
<mainClass>com.mycompany.App</mainClass>
</manifest>
<!-- it define some entries about your artifact -->
<manifestEntries>
<Build-Maven>Maven ${maven.version}</Build-Maven>
<Build-Java>${java.version}</Build-Java>
<Build-OS>${os.name}</Build-OS>
<Build-Label>${project.version}</Build-Label>
</manifestEntries>
</archive>
</configuration>
</plugin>
When you run the command mvn package|install, the following meta-inf/manifest.mf file will be created and added into the Jar.
If you need the dependency jar be in somewhere, that can be done easily, you will use maven-dependency-plugin to copy project dependencies to somewhere you want. you can copy into your project build directory into the manifest prefix folder defined
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.5.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/dependency-jars/
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
all dependencies will be in {project}/target/dependency-jars/
That approach not include any dependency into the jar all will be out the jar in somewhere you define.
You can configurate your projects using this approach as you need
whit this approach you only have to do mvn clean install and execute your jar
I hope this aproach be the solution that you need.
We have an Eclipse Plugin which we build using Maven and Tycho. Currently
however, we still provide all project dependencies through a bunch of manually
added JAR files and not by Maven. This is due to the following reasons: (1) The
dependencies are not available through a standard Eclipse update site (at least
not in a current version), (2) the dependencies are not available as bundles.
The biggest part of these dependencies are the Selenium libraries (API, Remote,
browser-specific libs and their transitive dependencies, such as Guava, etc.)
I've wasted hours, trying to pull those dependencies during our Maven build.
Following this SO question, I tried the p2-maven-plugin, created an update
site with our dependencies which I added to my Eclipse target platform. However,
during runtime, classes, which are referenced across different JARs could not be
loaded (I assume, from my very limited OSGi knowledge, because some
necessary information was missing in the MANIFEST.MF files). Here's an example
of the issue, when trying to create a RemoteWebDriver, which uses the
DesiredCapabilities class (both classes in different bundles):
Exception in thread "Thread-8" java.lang.NoClassDefFoundError: org/openqa/selenium/remote/DesiredCapabilities
at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:243)
at org.openqa.selenium.remote.RemoteWebDriver.<init>(RemoteWebDriver.java:126)
at org.openqa.selenium.remote.RemoteWebDriver.<init>(RemoteWebDriver.java:153)
…
Caused by: java.lang.ClassNotFoundException: org.openqa.selenium.remote.DesiredCapabilities cannot be found by org.seleniumhq.selenium.remote-driver_2.45.0
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:439)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:352)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:344)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:160)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 7 more
Is there anything I still need to take care of, when using the p2-maven-plugin? The relevant parts of the pom.xml looked like this:
<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.seleniumhq.selenium:selenium-remote-driver:2.45.0</id>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
Couldn't get it to work, so we're now using the maven-dependency-plugin with the copy-dependencies, which we execute during the Maven initialize phase to pull all necessary dependencies (contrary to my initial feeling, this can be combined with the pom.xml using the eclipse-plugin packaging and the "manifest first" approach). The relevant part looks like this:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>initialize</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
The Maven dependencies are then copied to target/dependency.
Only little issue: The Bundle-ClassPath in the MANIFEST.MF needs to be manually updated in case the name of a JAR file changes when updating Maven dependencies (e.g. commons-io-2.4.jar becomes commons-io-2.5.jar).
[edit] Revisiting this answer in regards to the last sentence above: The version numbers can be conveniently stripped through the following option: <stripVersion>true</stripVersion>. This means, the above library will be renamed to commons-io.jar and thus no paths need to be updated when a version number changes.
Another possibility:
Some jar files may be broken (if you're using Eclipse, it's commonplace hibernate-commons-annotations-4.0.1.Final.jar; invalid LOC header (bad signature)? ). To check this possibility, try manually opening the jar to see if it's okay.
I also build an Eclipse plugin with Maven and Tycho. I have the same problem: the bundle org.eclipse.team.svn.core and org.eclipse.team.svn.ui are not available through a standard Eclipse update site.
Maybe you can try this to solve this kind of problem:
In Dependencies, find the box Automated Management of
Dependencies.
Add the wanted plugin using Add...
Choose Analyze code and add dependencies to the MANIFEST.MF via: Import-Package
Click on Add Dependencies so that you find required packages in the box Imported Packages nearby.
Then you can run the Maven build.
my java project structure looks like below
MyJavaProject
|
src/main/java
|
src/test/java
my project link https://docs.google.com/file/d/0BytpaaWh1xMbb19XNDd4MURqMmc
please correct my code
My pom mentioned below:
How do i create a test module classes jar and main module classes jar with all maven dependencies.
Without running test module(only compile) i need to get test jar.What changes needed to my pom and what maven command i need to mention(or what maven goal i need to mention in eclipse).
When i used jar:test-jar (as per my pom) in the goal field ,test jar created with all classes some times but some times jar contains no class at all.
When i used compile assembly:single in the goal field ,main module classes jar created with all dependencies every time.
please can any one help me.i need a sample pom that creates main,test modules of a java project compiled classes jar with maven dependencies
i got answer:
goal as : mvn clean install -DskipTests
Add this in your pom.xml
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
I'm just starting to use Maven, (evaluating it, really) and I need to be able to quickly generate a JAR file for my application and a directory with all the dependencies (for example, lib) so that I can deploy those two to be run in a stand-alone manner. Generating the JAR file with the proper manifest is easy, but I do not know how to get Maven to copy the dependencies for the current project into a lib directory that I can deploy.
Since this is for a stand-alone Java applications, I am not interested in deploying to a Maven repository, that is also fairly trivial, or at least easily googleable.
I've found out how to do everything except copy the dependent JAR files into some specified directory. This is the workflow I'm looking for:
$ mvn clean
$ mvn package
$ cp -r target/{lib,myApp.jar} installLocation
Then, running myApp.jar from installLocation as a JAR file should "just work" regardless of my $CLASSPATH.
To try and pre-empt some answers:
I do have a Main-class: set, and it works fine.
I've also set the classpath in the MANIFEST.MF, and that works fine too.
I've found out how to use <classpathPrefix> and <classpathMavenRepositoryLayout> to make this work -- but only on my machine. (via: <classpathPrefix>${settings.localRepository}</classpathPrefix>)
What you want to investigate is Maven's dependency plugin. Add something similar to the following to pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<configuration>
<outputDirectory>
${project.build.directory}
</outputDirectory>
</configuration>
</plugin>
Then run mvn clean dependency:copy-dependencies to copy perform the copy. Combine this with the assembly plugin and you can package everything into a self contained archive for distribution.
I did not care for the Shade plugin since it rolls all the packages from all the jars together.
To include all of the external libs you can use the Dependency Plugin as mentioned above.
This example will create a "lib" directory under "target/classes" before the "package" phase.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>target/classes/lib</outputDirectory>
<overWriteIfNewer>true</overWriteIfNewer>
<excludeGroupIds>
junit,org.hamcrest,org.mockito,org.powermock,${project.groupId}
</excludeGroupIds>
</configuration>
</execution>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>sources</goal>
</goals>
</execution>
</executions>
<configuration>
<verbose>true</verbose>
<detail>true</detail>
<outputDirectory>${project.build.directory}</outputDirectory>
</configuration>
</plugin>
Take a look at maven's dependency plugin, specifically the copy-dependencies goal. The usage section describes how to do exactly what you want.
To do it from the command line just do:
$ mvn dependency:copy-dependencies -DoutputDirectory=OUTPUT_DIR
Yet another one is appassembler plugin
What I like about it is that it packages the app in a form ready to use (with a .bat file ans such)
It sure can. You need to use the shade plugin which can be done by adding
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.3-SNAPSHOT</version>
<configuration>
<!-- put your configurations here -->
</configuration>
</plugin>
to your project.
Using maven.repo.local one can collect all jars, but, they are collected into a directory with maven hierarchy (.m2).
mvn install -Dmaven.repo.local=./pick/some/folder
You can then collect them (on Linux):
mkdir flat-repo
find ./pick/some/folder -type f -name "*.jar" | xargs -I'{}' cp '{}' flat-repo/