Running JAR with maven-dependencies not contained in this JAR - java

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.

Related

java.lang.NoClassDefFoundError: org/telegram/telegrambots/meta/exceptions/TelegramApiException

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).

Maven: download source from github, compile into jar, include jar in WEB-INF/lib directory

There are many "solutions" to this issue which I have tried to no avail, so please forgive me if this seems redundant.
I have a Java/Maven project being built with Intellij IDEA which has a dependency on the jar file built from this GitHub project: https://github.com/protegeproject/snap-sparql-query
Unfortunately, the jar is NOT in any external repository so must be built by me. I have the build working and manually copy the jar into the WEB-INF/lib folder of my parent project. Intellij then runs correctly, all dependent jars are found at execution even though the resulting war file does not contain the snap-sparql-query jar. I'm guessing it is getting cached somewhere.
If I build the project from the command line ($ mvn clean package) it builds but the above jar file still is NOT included in the resulting war file, even if it exists in the WEB-INF/lib folder of the parent before being packaged as a war file.
The ideal solution would be Maven commands in the parent that:
download the source for snap-sparql-query
compile the source into a jar
copy the jar to the parent WEB-INF/lib directory
all jars in the WEB-INF/lib directory get included in the war file
At the very least I'd be satisfied manually performing items 1-3 above, but have Maven perform #4.
Here is the Maven entry for snap-sparql-query:
<!-- SNAP SPARQL API -->
<!-- https://github.com/protegeproject/snap-sparql-query -->
<dependency>
<groupId>edu.stanford.protege</groupId>
<artifactId>snap-sparql-query-api</artifactId>
<version>4.0.0-SNAPSHOT</version>
<!-- this library isn't found in the maven repository, must be externally compiled -->
<!-- and copied to the ...WEB-INF/lib directory so this pom can find it -->
<scope>system</scope>
<systemPath>${basedir}/WEB-INF/lib/snap-sparql-query-api-4.0.0-SNAPSHOT.jar</systemPath>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>edu.stanford.protege</groupId>
<artifactId>de-derivo-sparqldlapi</artifactId>
<version>2.0.0</version>
<!--<version>3.0.0</version>-->
</dependency>
I've been warned using the systemPath is bad, so I would like to avoid that too, if possible.
Can I have Maven perform at least item 4 above, and/or ideally 1-4?
You asked multiple things and in order to answer all, I need more
details. I will update the answer once you provide those details. But for now, below is the answer for the Item 4 in your list.
By default Maven will not include System scoped jars in the packaged application. In order to include System scoped dependencies you need to use maven-dependency-plugin's copy- dependency goal.
Please note the <phase>prepare-package</phase>. Having phase prepare-package is very important to include the dependencies in the WAR file since this goal needs to be executed before the execution of maven-war-plugin.
<build>
<finalName>maven-sys-scope</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dep</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>system</includeScope>
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

Why is my maven dependency in included .jar not found in final .war

I have a .jar we have developed in-house. It is built using maven. It has a dependency, commons-codec, that is provided from the maven central repository.
.jar .pom dependency ("myjar"):
<packaging>jar</packaging>
...
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
...
.war .pom dependency:
<packaging>war</packaging>
...
<dependency>
<groupId>com.myco.mydiv</groupId>
<artifactId>myjar</artifactId>
<version>1.5.54</version>
</dependency>
....
I can build and test this jar without issue. When the jar is included as a dependency in a .war, it builds without problem, but at run time, the external dependency for commons-codec produces a class def not found exception.
I tried changing the scope for commons-codec in the .jar .pom to 'compile' but this did not help.
I can fix this by adding the commons-codec dependency to the .war .pom, but this is not the right way to fix it (I think) as it requires all projects using the .jar to know about this dependency and include it likewise. I could also include the external .jar in the WEB-INF/lib to solve this, but it also seems like the incorrect approach.
What is the best way to handle this? Why is the common-codec dependency not visible at run time for the .war?
This conversation seems to touch on a similar issue: https://github.com/ReactiveX/RxNetty/issues/292
And so I wonder if there is a right way to handle this with nested dependencies.
But I just noticed this answer, which seems to show the right way to do this:
https://stackoverflow.com/a/98743/2266428
jar-with-dependencies via the maven-assembly-plugin seems to solve the problem but at the expense of a very large .jar (6 MB in my case).
After trying multiple approaches, it turns out the Shade plugin was exactly what was needed. The below added plugin configuration to my .war .pom, exactly as shown, added the dependency to the jar and made it available to the .war at runtime.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
</configuration>
</execution>
</executions>
</plugin>
Unzipping the initial .jar shows that the following path and classes are now included in the build:
org > apache > commmons > codec > *.class

Maven is not adding a library to the final JAR [duplicate]

I have a proprietary jar that I want to add to my pom as a dependency.
But I don't want to add it to a repository. The reason is that I want my usual maven commands such as mvn compile, etc, to work out of the box. (Without demanding from the developers a to add it to some repository by themselves).
I want the jar to be in a 3rdparty lib in source control, and link to it by relative path from the pom.xml file.
Can this be done? How?
I want the jar to be in a 3rdparty lib in source control, and link to it by relative path from the pom.xml file.
If you really want this (understand, if you can't use a corporate repository), then my advice would be to use a "file repository" local to the project and to not use a system scoped dependency. The system scoped should be avoided, such dependencies don't work well in many situation (e.g. in assembly), they cause more troubles than benefits.
So, instead, declare a repository local to the project:
<repositories>
<repository>
<id>my-local-repo</id>
<url>file://${project.basedir}/my-repo</url>
</repository>
</repositories>
Install your third party lib in there using install:install-file with the localRepositoryPath parameter:
mvn install:install-file -Dfile=<path-to-file> -DgroupId=<myGroup> \
-DartifactId=<myArtifactId> -Dversion=<myVersion> \
-Dpackaging=<myPackaging> -DlocalRepositoryPath=<path>
Update: It appears that install:install-file ignores the localRepositoryPath when using the version 2.2 of the plugin. However, it works with version 2.3 and later of the plugin. So use the fully qualified name of the plugin to specify the version:
mvn org.apache.maven.plugins:maven-install-plugin:2.3.1:install-file \
-Dfile=<path-to-file> -DgroupId=<myGroup> \
-DartifactId=<myArtifactId> -Dversion=<myVersion> \
-Dpackaging=<myPackaging> -DlocalRepositoryPath=<path>
maven-install-plugin documentation
Finally, declare it like any other dependency (but without the system scope):
<dependency>
<groupId>your.group.id</groupId>
<artifactId>3rdparty</artifactId>
<version>X.Y.Z</version>
</dependency>
This is IMHO a better solution than using a system scope as your dependency will be treated like a good citizen (e.g. it will be included in an assembly and so on).
Now, I have to mention that the "right way" to deal with this situation in a corporate environment (maybe not the case here) would be to use a corporate repository.
Using the system scope. ${basedir} is the directory of your pom.
<dependency>
<artifactId>..</artifactId>
<groupId>..</groupId>
<scope>system</scope>
<systemPath>${basedir}/lib/dependency.jar</systemPath>
</dependency>
However it is advisable that you install your jar in the repository, and not commit it to the SCM - after all that's what maven tries to eliminate.
This is another method in addition to my previous answer at Can I add jars to maven 2 build classpath without installing them?
This will get around the limit when using multi-module builds especially if the downloaded JAR is referenced in child projects outside of the parent. This also reduces the setup work by creating the POM and the SHA1 files as part of the build. It also allows the file to reside anywhere in the project without fixing the names or following the maven repository structure.
This uses the maven-install-plugin. For this to work, you need to set up a multi-module project and have a new project representing the build to install files into the local repository and ensure that one is first.
You multi-module project pom.xml would look like this:
<packaging>pom</packaging>
<modules>
<!-- The repository module must be first in order to ensure
that the local repository is populated -->
<module>repository</module>
<module>... other modules ...</module>
</modules>
The repository/pom.xml file will then contain the definitions to load up the JARs that are part of your project. The following are some snippets of the pom.xml file.
<artifactId>repository</artifactId>
<packaging>pom</packaging>
The pom packaging prevents this from doing any tests or compile or generating any jar file. The meat of the pom.xml is in the build section where the maven-install-plugin is used.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<executions>
<execution>
<id>com.ibm.db2:db2jcc</id>
<phase>verify</phase>
<goals>
<goal>install-file</goal>
</goals>
<configuration>
<groupId>com.ibm.db2</groupId>
<artifactId>db2jcc</artifactId>
<version>9.0.0</version>
<packaging>jar</packaging>
<file>${basedir}/src/jars/db2jcc.jar</file>
<createChecksum>true</createChecksum>
<generatePom>true</generatePom>
</configuration>
</execution>
<execution>...</execution>
</executions>
</plugin>
</plugins>
</build>
To install more than one file, just add more executions.
This is working for me:
Let's say I have this dependency
<dependency>
<groupId>com.company.app</groupId>
<artifactId>my-library</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/my-library.jar</systemPath>
</dependency>
Then, add the class-path for your system dependency manually like this
<Class-Path>libs/my-library-1.0.jar</Class-Path>
Full config:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifestEntries>
<Build-Jdk>${jdk.version}</Build-Jdk>
<Implementation-Title>${project.name}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Specification-Title>${project.name} Library</Specification-Title>
<Specification-Version>${project.version}</Specification-Version>
<Class-Path>libs/my-library-1.0.jar</Class-Path>
</manifestEntries>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.company.app.MainClass</mainClass>
<classpathPrefix>libs/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
<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}/libs/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
Basically, add this to the pom.xml:
...
<repositories>
<repository>
<id>lib_id</id>
<url>file://${project.basedir}/lib</url>
</repository>
</repositories>
...
<dependencies>
...
<dependency>
<groupId>com.mylibrary</groupId>
<artifactId>mylibraryname</artifactId>
<version>1.0.0</version>
</dependency>
...
</dependencies>
I've previously written about a pattern for doing this.
It is very similar to the solution proposed by Pascal, though it moves all such dependencies into a dedicated repository module so that you don't have to repeat it everywhere the dependency is used if it is a multi-module build.
we switched to gradle and this works much better in gradle ;). we just specify a folder we can drop jars into for temporary situations like that. We still have most of our jars defined i the typicaly dependency management section(ie. the same as maven). This is just one more dependency we define.
so basically now we can just drop any jar we want into our lib dir for temporary testing if it is not a in maven repository somewhere.
One small addition to the solution posted by Pascal
When I followed this route, I got an error in maven while installing ojdbc jar.
[INFO] --- maven-install-plugin:2.5.1:install-file (default-cli) # validator ---
[INFO] pom.xml not found in ojdbc14.jar
After adding -DpomFile, the problem was resolved.
$ mvn install:install-file -Dfile=./lib/ojdbc14.jar -DgroupId=ojdbc \
-DartifactId=ojdbc -Dversion=14 -Dpackaging=jar -DlocalRepositoryPath=./repo \
-DpomFile=~/.m2/repository/ojdbc/ojdbc/14/ojdbc-14.pom
I was facing with the same issue, and it works just removing the DlocalRepositoryPath parameter and defining the correct path from current location in the Dfile parameter:
mvn install:install-file -Dfile=./repo/com/tridion/cd_core/1.0/cd_core-1.0.jar -DgroupId=com.tridion -DartifactId=cd_core -Dversion=1.0 -Dpackaging=jar
Note: Apache Maven 3.8.6
You can use eclipse to generate a runnable Jar :
Export/Runable Jar file

Maven: add a dependency to a jar by relative path

I have a proprietary jar that I want to add to my pom as a dependency.
But I don't want to add it to a repository. The reason is that I want my usual maven commands such as mvn compile, etc, to work out of the box. (Without demanding from the developers a to add it to some repository by themselves).
I want the jar to be in a 3rdparty lib in source control, and link to it by relative path from the pom.xml file.
Can this be done? How?
I want the jar to be in a 3rdparty lib in source control, and link to it by relative path from the pom.xml file.
If you really want this (understand, if you can't use a corporate repository), then my advice would be to use a "file repository" local to the project and to not use a system scoped dependency. The system scoped should be avoided, such dependencies don't work well in many situation (e.g. in assembly), they cause more troubles than benefits.
So, instead, declare a repository local to the project:
<repositories>
<repository>
<id>my-local-repo</id>
<url>file://${project.basedir}/my-repo</url>
</repository>
</repositories>
Install your third party lib in there using install:install-file with the localRepositoryPath parameter:
mvn install:install-file -Dfile=<path-to-file> -DgroupId=<myGroup> \
-DartifactId=<myArtifactId> -Dversion=<myVersion> \
-Dpackaging=<myPackaging> -DlocalRepositoryPath=<path>
Update: It appears that install:install-file ignores the localRepositoryPath when using the version 2.2 of the plugin. However, it works with version 2.3 and later of the plugin. So use the fully qualified name of the plugin to specify the version:
mvn org.apache.maven.plugins:maven-install-plugin:2.3.1:install-file \
-Dfile=<path-to-file> -DgroupId=<myGroup> \
-DartifactId=<myArtifactId> -Dversion=<myVersion> \
-Dpackaging=<myPackaging> -DlocalRepositoryPath=<path>
maven-install-plugin documentation
Finally, declare it like any other dependency (but without the system scope):
<dependency>
<groupId>your.group.id</groupId>
<artifactId>3rdparty</artifactId>
<version>X.Y.Z</version>
</dependency>
This is IMHO a better solution than using a system scope as your dependency will be treated like a good citizen (e.g. it will be included in an assembly and so on).
Now, I have to mention that the "right way" to deal with this situation in a corporate environment (maybe not the case here) would be to use a corporate repository.
Using the system scope. ${basedir} is the directory of your pom.
<dependency>
<artifactId>..</artifactId>
<groupId>..</groupId>
<scope>system</scope>
<systemPath>${basedir}/lib/dependency.jar</systemPath>
</dependency>
However it is advisable that you install your jar in the repository, and not commit it to the SCM - after all that's what maven tries to eliminate.
This is another method in addition to my previous answer at Can I add jars to maven 2 build classpath without installing them?
This will get around the limit when using multi-module builds especially if the downloaded JAR is referenced in child projects outside of the parent. This also reduces the setup work by creating the POM and the SHA1 files as part of the build. It also allows the file to reside anywhere in the project without fixing the names or following the maven repository structure.
This uses the maven-install-plugin. For this to work, you need to set up a multi-module project and have a new project representing the build to install files into the local repository and ensure that one is first.
You multi-module project pom.xml would look like this:
<packaging>pom</packaging>
<modules>
<!-- The repository module must be first in order to ensure
that the local repository is populated -->
<module>repository</module>
<module>... other modules ...</module>
</modules>
The repository/pom.xml file will then contain the definitions to load up the JARs that are part of your project. The following are some snippets of the pom.xml file.
<artifactId>repository</artifactId>
<packaging>pom</packaging>
The pom packaging prevents this from doing any tests or compile or generating any jar file. The meat of the pom.xml is in the build section where the maven-install-plugin is used.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<executions>
<execution>
<id>com.ibm.db2:db2jcc</id>
<phase>verify</phase>
<goals>
<goal>install-file</goal>
</goals>
<configuration>
<groupId>com.ibm.db2</groupId>
<artifactId>db2jcc</artifactId>
<version>9.0.0</version>
<packaging>jar</packaging>
<file>${basedir}/src/jars/db2jcc.jar</file>
<createChecksum>true</createChecksum>
<generatePom>true</generatePom>
</configuration>
</execution>
<execution>...</execution>
</executions>
</plugin>
</plugins>
</build>
To install more than one file, just add more executions.
This is working for me:
Let's say I have this dependency
<dependency>
<groupId>com.company.app</groupId>
<artifactId>my-library</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/my-library.jar</systemPath>
</dependency>
Then, add the class-path for your system dependency manually like this
<Class-Path>libs/my-library-1.0.jar</Class-Path>
Full config:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifestEntries>
<Build-Jdk>${jdk.version}</Build-Jdk>
<Implementation-Title>${project.name}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Specification-Title>${project.name} Library</Specification-Title>
<Specification-Version>${project.version}</Specification-Version>
<Class-Path>libs/my-library-1.0.jar</Class-Path>
</manifestEntries>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.company.app.MainClass</mainClass>
<classpathPrefix>libs/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
<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}/libs/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
Basically, add this to the pom.xml:
...
<repositories>
<repository>
<id>lib_id</id>
<url>file://${project.basedir}/lib</url>
</repository>
</repositories>
...
<dependencies>
...
<dependency>
<groupId>com.mylibrary</groupId>
<artifactId>mylibraryname</artifactId>
<version>1.0.0</version>
</dependency>
...
</dependencies>
I've previously written about a pattern for doing this.
It is very similar to the solution proposed by Pascal, though it moves all such dependencies into a dedicated repository module so that you don't have to repeat it everywhere the dependency is used if it is a multi-module build.
we switched to gradle and this works much better in gradle ;). we just specify a folder we can drop jars into for temporary situations like that. We still have most of our jars defined i the typicaly dependency management section(ie. the same as maven). This is just one more dependency we define.
so basically now we can just drop any jar we want into our lib dir for temporary testing if it is not a in maven repository somewhere.
One small addition to the solution posted by Pascal
When I followed this route, I got an error in maven while installing ojdbc jar.
[INFO] --- maven-install-plugin:2.5.1:install-file (default-cli) # validator ---
[INFO] pom.xml not found in ojdbc14.jar
After adding -DpomFile, the problem was resolved.
$ mvn install:install-file -Dfile=./lib/ojdbc14.jar -DgroupId=ojdbc \
-DartifactId=ojdbc -Dversion=14 -Dpackaging=jar -DlocalRepositoryPath=./repo \
-DpomFile=~/.m2/repository/ojdbc/ojdbc/14/ojdbc-14.pom
I was facing with the same issue, and it works just removing the DlocalRepositoryPath parameter and defining the correct path from current location in the Dfile parameter:
mvn install:install-file -Dfile=./repo/com/tridion/cd_core/1.0/cd_core-1.0.jar -DgroupId=com.tridion -DartifactId=cd_core -Dversion=1.0 -Dpackaging=jar
Note: Apache Maven 3.8.6
You can use eclipse to generate a runnable Jar :
Export/Runable Jar file

Categories

Resources