My challenge is simple: I am creating a small Java application – single class with main method – that has many direct and indirect dependencies. In order to run my simple class locally I need to:
- code the Java Class
- compile the class
- run the class
In order to compile the class, all directly referenced classes from supporting libraries should be available. To run the class, all indirectly invoked classes should also be available. That means that in addition to the .class file that is result of compiling my Java code, I need a large number of JAR-files.
Maven is a great mechanism for describing the dependencies of a project. With a few simple XML elements, I can indicate which libraries my application has a direct dependency on. The Maven pom.xml file is where these dependencies are described. Maven uses these dependencies during compilation – to have all direct dependent classes available for the compiler.
In order to help out with all run time dependencies, Maven also can download all jar-files for the direct and even the indirect dependencies. Take the dependencies in this pom.xml file (for a Java application that will work with Kafka Streams):
<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>nl.amis.streams.countries</groupId> <artifactId>Country-Events-Analyzer</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>Country-Events-Analyzer</name> <url>http://maven.apache.org</url> <dependencies> <!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-streams --> <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-streams</artifactId> <version>0.10.0.0</version> </dependency> <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>0.10.0.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.7.4</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.rocksdb</groupId> <artifactId>rocksdbjni</artifactId> <version>4.9.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
The number of JAR files required to eventually run the generated class is substantially. To find all these JAR-files manually is not simple: it may not be so simple to determine which files are required, the files may not be easy to locate and the indirect dependencies (stemming from the JAR files that the application directly depends on) are almost impossible to determine.
Using a simple Maven instruction, all JAR files are gathered and copied to a designated directory. Before the operation, here is the application. Note that the target directory is empty.
The statement to use is:
mvn install dependency:copy-dependencies
This will instruct Maven to analyze the pom.xml file, find the direct dependencies, find the associated JAR files, determine the indirect dependencies for each of these direct dependencies and process them similarly and recursively.
after some dozens of seconds:
The JAR files are downloaded to the target/dependency directory:
I can now run my simple application using this command line command, that adds all JAR files to the classpath for the JVM:
java -cp target/Country-Events-Analyzer-1.0-SNAPSHOT.jar;target/dependency/* nl.amis.streams.countries.App
Note: on Linux, the semi colon should be a colon: java -cp target/Country-Events-Analyzer-1.0-SNAPSHOT.jar:target/dependency/* nl.amis.streams.countries.App
Note: the maven dependencies for specific projects and libraries can be explored in MVNRepository , such as https://mvnrepository.com/artifact/org.apache.kafka/kafka-streams/0.10.0.0 for Kafka Streams.
Thanks Lucas.
This deed help me some what, However the “dependency:copy-dependencies” mojo seems to copy only the compile time dependencies. It seems to miss run-time dependencies.
Specifically I was trying a simple java class to read from excel sheet using Apache POI. The above command downloaded 6 jars to the dependencies folder.
I was able to compile my .java file to a .class file using these jars. However when I tried to run this complied class file, I kept on running into multiple “ClassNotFoundException” run-time exceptions.
I had to manually download 4 additional jars one by one to resolve the run-time exceptions.
Note that I did not have to compile my program again, Only needed to provide additional jars to resolve run-time dependencies.
Any suggestions on how to identify and download all run-time dependencies?