Maven: how to query the executable classpath? - java

I have a maven project with some specified dependencies.
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
How can I query maven to find out the path it's using for these dependencies, or the classpath I should use for independent execution?
My goal is to build a wrapper which runs the program with the appropriate classpath.

Several alternatives are available in Maven:
Maven Dependency Plugin (build-classpath goal)
Look at the Maven Dependency Plugin, especially the build-classpath goal provides exactly the full classpath for external execution usages. Among many options, The outputFile parameter may be helpful.
You don't need to configure it for usage, just run
mvn dependency:build-classpath
On your project and you'll see the classpath as part of the build output. Or
mvn dependency:build-classpath -Dmdep.outputFile=classpath.txt
To redirect just the classpath to a file.
Maven Dependency Plugin (copy-dependencies goal)
To build a wrapper, you could also look at the copy-dependencies goal, which would copy the required dependencies (jars), including transitive dependencies, to a configured folder (so you don't need hardcoded paths to your local machine).
An example of plugin configuration is available on the official site, here.
For instance, the following configuration:
<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>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/dependencies</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Would add to the folder target/dependencies all the dependencies declared in scope compile. NOTE: with respect to the linked official example, I added the <includeScope>runtime</includeScope> configuration entry (which will include compile and runtime scoped dependencies, according to documentation and my tests), otherwise it would also include the test scope by default (which is something I believe you would not need at runtime).
Exec Maven Plugin (java or exec goals)
Alternatively, you can use the Exec Maven Plugin to execute a main from Maven using the required classpath.
An example of plugin configuration is available on the official site, here.
The following configuration for instance:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>my-execution</id>
<phase>package</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.sample.MainApp</mainClass>
</configuration>
</plugin>
Will configure the Exec plugin to run via mvn exec:java the main class MainApp as configured, obviously with the required classpath.
Maven Assembly Plugin
Lastly, the Maven Assembly Plugin also provides facilities to build an executable jar with dependencies, as explained here, in another question on stackoverflow.

Related

Maven dependencies not being compiled

I have been trying for the last hour or so to get my Maven project to include source files from its dependencies, but for some reason, it isn't. I have followed the steps provided by the following link, but when I compile and run the plugin, I get a ClassNotFoundException:
https://github.com/mkremins/fanciful
I have made sure to include the dependencies and the repository from the link above into my pom.xml file, but when I compile, they don't get added to my .jar file.
I am fairly new to using Maven, and like it so far, albeit that it can be a pain to solve issues like this.
I am building the project by doing the following:
Right click project -> Run As -> Maven Build -> Goal: clean install
EDIT -
With a little more searching around, I figured it wasn't as easy as I thought so. I added the following to my pom.xml build section:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<minimizeJar>true</minimizeJar>
<artifactSet>
<includes>
<include>mkremins:fanciful</include>
<include>org.json:json</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
The only problem with this is that I needed to also manually include the dependencies of the main library I wanted to use - mkremins:fanciful; is there flag or option to automatically copy dependencies from the one file I need, rather than also including <include>org.json:json</include>?
Well, if you want to have your dependencies copied to your target jar, you need to tell maven to do so! Maven doesn't know if the artifact of your project is meant to be self-sufficient executable jar, jar to be executed inside a container or just a dependency or library for another project.
You might want to use copy-dependencies task from maven-dependency-plugin
For example:
<build>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
<outputDirectory>${project.build.directory}</outputDirectory>
<excludeTransitive>false</excludeTransitive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
For more tweaking you might also want to play with jar plugin and assembly plugin. On more about creating executable jars:
http://www.ibm.com/developerworks/java/library/j-5things13/index.html?ca=dat-
You have mistaken the idea of Maven. Maven is intended to use dependencies which are located in Maven Central. It's idea is not to compile dependencies. I recommend you to read about Maven and learn how it works.

Maven won't add local dependency to target jar

I have a maven project that besides using normal repos also uses a local jar. The jar is defined in the manifest this way:
<dependency>
<groupId>com.mirrorworlds</groupId>
<artifactId>lstnef</artifactId>
<version>1.0.0</version>
<optional>false</optional>
<scope>system</scope>
<systemPath>${basedir}/lib/lstnef-1.0.0.jar</systemPath>
</dependency>
The install script works successfully, but after the app is launched I get this:
Exception in thread "main" java.lang.NoClassDefFoundError:
com/mirrorworlds/lifestreams/mail/tnef/internet/TnefMultipart
at ...processMails(MailProcessor.java:57)
at ...main(MailReader.java:42)
When I look inside the target jar I can't find these classes as well, though they are supposed to be inside lstnef-1.0.0.jar
I'll be thankful for any suggestions on solving this mystery.
Check the Maven docs: http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope
system
This scope is similar to provided except that you have to provide the JAR which contains it explicitly. The artifact is always available and is not looked up in a repository.
You will need to manually provide this JAR to the runtime environment yourself.
Or, and I would reccommend this approach, setup your own repository that you can add JARS to and manage them in the normal maven way
Possible solution I use is installing this system JAR into the local Maven repository before compilation phase and then reference this JAR as a Maven artifact. I.e.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>your-file</id>
<inherited>false</inherited>
<phase>validate</phase>
<configuration>
<file>${pom.basedir}/lib/your-file-4.8.jar</file>
<repositoryLayout>default</repositoryLayout>
<groupId>your-file</groupId>
<artifactId>your-file</artifactId>
<version>4.8</version>
<packaging>jar</packaging>
<generatePom>true</generatePom>
</configuration>
<goals>
<goal>install-file</goal>
</goals>
</execution>
</executions>
</plugin>
And then reference it:
<dependency>
<groupId>your-file</groupId>
<artifactId>your-file</artifactId>
<version>4.8</version>
</dependency>
Using the system scope tells maven that the dependency is available during maven "working-hours" at the system location that you provide (this is the difference to the provided scope that makes use of normal dependency resolution instead).
After that you have to "provide" the file by yourself - eg by putting it into the CLASSPATH (hence the similarity to the provided scope). To install the file to your local repository cache you could refer to this article:
http://maven.apache.org/plugins/maven-install-plugin/examples/specific-local-repo.html
You can just ommit the localrepository path and maven will install in his local "cache" where it looks up any dependencies before going to remote repositories.
Maven will also suport you when you build a manifest.mf with Class-Path entry (e.g. when your application is running on localhost): To see how it works read here.
you need to use shade plugin
http://maven.apache.org/plugins/maven-shade-plugin/
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>org.sonatype.haven.ExodusCli</Main-Class>
<Build-Number>123</Build-Number>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
To install local jar to local repository, do something like below.
mvn install:install-file -Dfile=lib/ojdbc6.jar -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.4 -Dpackaging=jar

Multiple install:install-file in a single pom.xml

(Please read at least this before answering: This is a temporary measure! No, we do not want to set up a local repository manager and manually run a script)
We have a legacy project with a few dependencies which we have a local copy of including source and javadoc, and which has been proven to work well in production, but which is not available in the same quality in Central. We want to use those jars we already have.
I have found that I can manually run a suitably complex mvn install:install-file command to get the artifacts injected in the repository of the local machine, but I would like to have it work as part of the normal maven build of our various modules.
Given I have an otherwise blank module containing multiple jars which each need to be inserted with an install:install-file how should I do this in my pom.xml to be fully conformant with the normal Maven build?
Or can I just attach multiple jars to be the output of the module and somehow attach javadoc and source too)?
(and, please, no suggestion about submitting to central or setting up a local repository manager. This is a temporary solution until we have an opportunity to upgrade to a newer version of the dependencies)
I would imagine something like this would work (this will install it on every build):
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<executions>
<execution>
<id>inst_1</id>
<phase>initialize</phase>
<goals>
<goal>install-file</goal>
</goals>
<configuration>
<!-- config for file 1 -->
</configuration>
</execution>
<execution>
<id>inst_2</id>
<phase>initialize</phase>
<goals>
<goal>install-file</goal>
</goals>
<configuration>
<!-- config for file 2 -->
</configuration>
</execution>
<!-- execution file 3... -->
</executions>
</plugin>
</plugins>
</build>

how to use class file from another war

We have two different web application and we want to extend few controllers of one war into another war.
We are using maven to build the project.
to include war we have given its dependency as
<dependency>
<groupId>com.abc.exchange</groupId>
<artifactId>employer</artifactId>
<version>2.3.M2-SNAPSHOT</version>
<type>war</type>
<scope>compile</scope>
</dependency>
It is unable to build giving class not found exception.
Can any body help me out how to achieve this?
I am getting error maven build failed :
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile (default-compile) on project agent-war: Compilation failure: Compilation failure:
[ERROR] \projects\trunk_new\agent\src\main\java\com\platform\agent\web\AgentEmployeeController.java:[22,41] cannot find symbol
[ERROR] symbol : class EmployeeController
[ERROR] location: package com..platform.employer.web
You can define the war plugin to produce a separate jar file which is available via a classifier based on the configuration:
<configuration>
..
<attachClasses>true</attachClasses>
<archiveClasses>true</archiveClasses>
</configuration>
After that you can use this as a separate dependency in other projects. But the best to make a separate jar module out of it.
What you are doing is using a WAR file overlay. Maven does support this. However...
The WAR plugin executes in the package phase. Any plugin, such as the Java compiler (which runs in the compile phase), that executes before this phase will not see any files that the WAR plugin has extracted. (here is the reference list of all Maven phases if that helps)
If you have the ability to refactor your project structure, the best way is to create a normal JAR project with your controllers and have both WARs pull this JAR in as a dependency.
If there is some reason why you can't do this, you will need to do something like:
Configure the WAR plugin to run in a phase earlier than compile, such as generate-resources and makes sure it extracts the overlay class files to ${project.build.outputDirectory}.
You could also use the Maven Dependency Plugin's unpack goal to extract classes from the dependency WAR to ${project.build.outputDirectory}.
But I do recommend if at all possible to refactor your controllers into a separate JAR, it is much easier and more maintainable.
put the controllers into a new jar project and make dependencies from your webprojects to this controllers.
Add the following plugins to your share maven war module (for creating war and jar artifact at the same time):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>make-a-jar</id>
<phase>compile</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>install-file</goal>
</goals>
<configuration>
<packaging>jar</packaging>
<artifactId>${project.artifactId}</artifactId>
<groupId>${project.groupId}</groupId>
<version>${project.version}</version>
<file>
${project.build.directory}/${project.artifactId}-${project.version}.jar
</file>
</configuration>
</execution>
</executions>
</plugin>
then add dependency to your dependent maven war module.
Java EE visability standards state that classes from one war shouldn't be available to classes in another war, when they're packaged as an EAR. Most containers will enforce this strictly.
You should put the code you wish to share into a JAR and include that as a dependency in the war you want to use.
In the war project pom.xml include
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
This will create your-project-0.0.1-SNAPSHOT-clases.jar in the target folder along with the war.
In the dependent project pom.xml include
<dependency>
<groupId>com.yourproject</groupId>
<artifactId>you-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<classifier>classes</classifier>
</dependency>
This worked for me. Hope it helps.
Edit: If we want only some class files into the jar then add this to pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>make-a-jar</id>
<phase>compile</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>classifier_name</classifier>
<includes>
<include>com/../..</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
In the dependent project pom.xml include
<dependency>
<groupId>com.yourproject</groupId>
<artifactId>you-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<classifier>classifier_name</classifier>
</dependency>
note: the classifier name must be same in both pom.xml files

How to deploy the sources file with the jar using deploy:deploy-file

I have the following plugins for creating a -sources.jar and deploying a specific named jar to a repository.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.5</version>
<configuration>
<version>${project.version}-r${buildNumber}</version>
<classifier>${env}</classifier>
<packaging>jar</packaging>
<file>${project.build.directory}/${project.build.finalName}.jar</file>
<url>${artifactory.url}/libs-release-local</url>
<repositoryId>artifactory.digiterre.com</repositoryId>
<pomFile>${project.basedir}/pom.xml</pomFile>
</configuration>
</plugin>
I wish to deploy the *-sources.jar at the same time. I have tried adding a second file entry and even a second deploy plugin. I seem to get one or other file deployed.
Is it possible to deploy both in one pass using deploy:deploy-file or will I have to set up a second team city build just to deploy the sources?
When you use maven-source-plugin, the generated jar will automatically attach to project artifact (default setting for this parameter is 'true') and if you execute deploy it will be deployed along with it. Alas, no need for separate configuration of deploy plugin.
Unfortunately, you cannot add classifier (${env} in your case) to sources jar. That is why I'd use the following configuration:
...
<artifactId>com.pie.mash.repo.mince-${env}</artifactId>
<version>1.18-r${buildNumber}</version>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Also, I've found this question on SO. You can use the workaround suggested there.
We can use deploy:deploy-file to upload multiple JARs (sources, tests, docs) along side main JAR artifact. We just need to supply that additional piece of information to deploy:deploy-file plugin call. The additions are indicated in bold in below command:
mvn deploy:deploy-file
-Dfile=helloWorld.jar
-Durl=https://localhost/nexus/content/repositories/snapshots/
-DrepositoryId=snapshot
-Dfiles=helloWorld-6.4.1.3.SNAPSHOT-sources.jar,helloWorld-6.4.1.3.SNAPSHOT-tests.jar
-Dtypes=jar,jar -Dclassifiers=sources,tests
-DgroupId=com
-DartifactId=helloWorld
-Dversion=6.4.1.3.SNAPSHOT
-Dpackaging=jar
-Dpomfile=pom.xml
We need to specify list of files separated by commas.
We need to specify the types of those additional files.
We need to add classifier information for those additional files.
mvn deploy:deploy-file only deploys a single artifact. Instead you can use mvn deploy (which invokes mvn deploy:deploy) to deploy the artifact, its pom along with the attached artifacts (like source and javadoc). Refer to the goals overview of maven deploy plugin.

Categories

Resources