How to Exclude Certain Jar Dependencies while creating jar without using maven? - maven

I am working on a core Java project. I am writing an Apache Storm topology and need to exclude storm jars while binding the topology into jar. Is there any way to do this without using maven? I know with maven we can use <scope>provided</scope> but I need an alternative to this.
PS: I am using Eclipse.

I use Gradle for compiling the JAR files for topologies. It allows you to exclude certain files when generating JAR files.
The example below shows the set-up that I use in my build.gradle file
apply plugin: 'java'
apply plugin: 'eclipse'
configurations {
provided
compile.extendsFrom provided
}
jar {
dependsOn configurations.runtime
from {
(configurations.runtime - configurations.provided).collect {
it.isDirectory() ? it : zipTree(it)
}
}
manifest {
attributes 'Main-Class': 'com.example.myclass'
}
}
dependencies {
provided files('./lib/asm-4.0.jar')
provided files('./lib/carbonite-1.4.0.jar')
# ... The rest of the Storm jars found in the lib directory of your storm installation
}
By default the directory structure Gradle expects is
MyProjectName
- build.gradle
- src
- main
- java
- [Your Java Files]
- resources
- resources
- [Mutlilang files / other resources]
From the command line when you run gradle build in the directory containing your build.gradle file a JAR file should be generated under .\build\libs
There is also a Gradle plugin for eclipse

If you are using Maven instead of Gradle, and you come here for excluding lib of Storm in building, I have the solution and a working example.
The documentation of Storm tells us to exclude the Storm dependency and provides a link to a page of Maven, which explains how to do it but it lacks a full example. It turns out that we have to create another XML file as the descriptor of assembly configuration, instead of putting the configuration directly in the pom.xml, even when Eclipse does not complain about putting the two files together.
Here is how:
We have our pom.xml with assembly plugins, pointing to another descriptor xml file:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<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>
<configuration>
<descriptors>
<descriptor>/src/main/resources/exclude-storm.xml</descriptor>
</descriptors>
<archive>
<manifest>
<mainClass>path.to.main.class</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
Note the part of: (should be complete path)
<descriptors>
<descriptor>/src/main/resources/exclude-storm.xml</descriptor>
</descriptors>
And in this path:
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>exclude-storm</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>false</useProjectArtifact>
<unpack>true</unpack>
<scope>compile</scope> <!-- note here!!!! -->
<excludes>
<exclude>org.apache.storm:storm-core:jar:1.1.1</exclude>
</excludes>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<outputDirectory>/</outputDirectory>
<directory>${project.build.outputDirectory}</directory>
</fileSet>
</fileSets>
</assembly>
Here we add the settings of Maven doc page.
The most important thing: format of exclusion: should be: (ref)
groupId:artifactId:type[:classifier]:version
And the scope! runtime is default, I changed it to compile and it works.
At last, when you compile, use:
clean assembly:assembly
And turn on debug output to see full output in console. If you:
have a successful build
search the output and haven't found anything like: [WARNING]The following patterns were never triggered in this artifact inclusion filter: o 'org.apache.storm:storm-core:jar:1.1.1'.
the jar contains no default.yaml
Then you know you have succeeded.
Thanks for the inspiration of another question and answers: How to exclude dependencies from maven assembly plugin : jar-with-dependencies?

Related

Maven: Three Jars in one project. Trying to use an assembly, but not getting pom.xml and pom.properties embedded in the jars

I have a project that produces three different jar files:
Server.jar: This contains all classes and resources. A standard jar
Client.jar: This contains only a few external classes and no resources.
ServerSDK.jar: This contains all the classes, resources, test classes, and other configuration files.
I've decided to do all three jars in a single project, so a change in any of the sources spawns a Jenkins build and deploys all three at once. I build the Server.jar as my standard pom.xml jar. Then, I use assemblies to build the Client.jar and the ServerSDK.jar.
I have the assemblies that build the other two jars, and everything is 99% of the way I like it, but there is bit of munging I'd like to do.
We add a few entries in our MANIFEST.MF file to incorporate the Jenkins build information and project information.
In a standard Maven jar, the pom.xml and pom.properties are embedded in the META-INF directory.
The first one I have managed to do via the <assembly> configuration in my maven-assembly-plugin. The second one I can't seem to get to work even though I have <addMavenDescriptor> set to true in my <assembly> configuration.
Here's my maven-assembly-plugin section in my pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<addMavenDescriptor>true</addMavenDescriptor>
<manifestSections>
<manifestSection>
<name>Build-Information</name>
<manifestEntries>
<Project-Name>${env.JOB_NAME}</Project-Name>
<Build-Number>${env.BUILD_NUMBER}</Build-Number>
<SVN-Revision>${env.SVN_REVISION}</SVN-Revision>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>Module-Information</name>
<manifestEntries>
<Group-ID>${project.groupId}</Group-ID>
<Artifact-ID>${project.artifactId}</Artifact-ID>
<Version>${project.version}</Version>
</manifestEntries>
</manifestSection>
</manifestSections>
</archive>
</configuration>
<executions>
<execution>
<id>Client</id>
<configuration>
<finalName>Client</finalName>
<appendAssemblyId>true</appendAssemblyId>
<descriptors>
<descriptor>src/assembly/client.xml</descriptor>
</descriptors>
</configuration>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
The <manifestSections> work just fine, but the <addMavenDescriptor> doesn't seem to be working although I've explicitly set it to true.
According to the documentation on the maven-archiver-plugin:
Whether the created archive will contain these two Maven files:
The pom file, located in the archive in META-INF/maven/${groupId}/${artifactId}/pom.xml
A pom.properties file, located in the archive in META-INF/maven/${groupId}/${artifactId}/pom.properties
The default value is true.
According the maven-assembly-plugin page:
<archive>
This is a set of instructions to the archive builder, especially for building .jar files. It enables you to specify a Manifest file for the jar, in addition to other options. See Maven Archiver Reference
Is there something simple I'm missing here?
The Maven Assembly Plugin actually ignores the addMavenDescriptor parameter, and will never include the Maven descriptor in the resulting assembly. This can be seen in the source code: only the META-INF/MANIFEST.MF file is possibly added to the JAR archive.
I couldn't find an existing JIRA issue about this, so I went ahead and created MASSEMBLY-835 to track this.
A work-around for now would be to add the files yourself in the assembly descriptor:
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
<id>client</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<files>
<file>
<source>pom.xml</source>
<outputDirectory>META-INF/maven/${project.groupId}/${project.artifactId}</outputDirectory>
</file>
<file>
<source>${project.build.directory}/maven-archiver/pom.properties</source>
<outputDirectory>META-INF/maven/${project.groupId}/${project.artifactId}</outputDirectory>
</file>
</files>
<!-- rest of your configuration -->
</assembly>
This adds a <files> configuration that adds the pom.xml and the generated pom.properties into the target directory.
Note that the pom.properties is generated by the Maven Archiver component during the default package goal into the target/maven-archiver directory; therefore, in order for it to be present when making your assembly, the Assembly Plugin has to be bound to the phase package (or later in the lifecycle), and the current Maven project needs to be of packaging JAR / WAR / EAR / EJB / RAR... but not POM which doesn't package an archive. The primary artifact of the Maven project also needs to be built (if you skip the generation of the primary JAR of a JAR project, the pom.properties won't be generated).
This works in a large majority of cases. But if you want a bullet-proof solution, you can just create the file yourself. Create a pom.properties somewhere in your project (example, base directory) with the following content:
#Generated by Apache Maven ${maven.version}
version=${project.version}
groupId=${project.groupId}
artifactId=${project.artifactId}
and in the previous assembly descriptor, have instead:
<file>
<source>pom.properties</source>
<outputDirectory>META-INF/maven/${project.groupId}/${project.artifactId}</outputDirectory>
<filtered>true</filtered>
</file>
This would correctly replace the placeholders inside the pom.properties that was created, and mimic what Maven Archiver would do.

Maven - using assembly plugin in multi-module project to create distribution file

I'm using Maven to build a multi module project;
which comprises of 9 war modules
Each module has its own POM containing instructions on how to package;
<packaging>war</packaging>
A parent POM is then responsible for initiating the Maven lifecycle on each module and pushing to an artifact manager (Nexus)
<modules>
<module>module1</module>
<module>module2....
I would like to use the assembly plugin to package each of the WAR files which were built earlier by each module into a single ZIP file. I'm attempting to do this by defining an assembly descriptor in the parent POM which defines a separate dependencySet for each of the modules (using groupID, artifactID and version to find the WAR in my local repo).
I've tried to achieve this using the following assembly file;
<assembly>
<id>war</id>
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>zip</format>
</formats>
<dependencySets>
<dependencySet>
<useProjectArtifact>false</useProjectArtifact>
<includes>
<include>com:test-web:war:${pom.version}</include>
</includes>
<outputFileNameMapping>test-web.war</outputFileNameMapping>
</dependencySet>
</dependencySets>
</assembly>
And this is the plugin configuration in my parent POM;
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.3</version>
<executions>
<execution>
<id>distribution-package</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<runOnlyAtExecutionRoot>true</runOnlyAtExecutionRoot>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
</configuration>
</execution>
</executions>
</plugin>
Is this approach on the right track?
Additionally does it make sense to pull the WAR files from my local repo? Should i be using the output in each of the sub modules target folders instead?
1) In your parent pom I would go like
<modules>
<module>module1</module>
<module>distibution</module>
<module>module2....
(create an extra module for the distribution) In order to separate the parent pom from the distribution.
2) You should not be using the output in each of the sub modules target folders. Add all wars as dependencies of the distribution. In that way maven can know that it must build the distribution LAST.
3) Tip: replace ${pom.version} with ${project.version} (I think the former is deprecated if it works at all)

build-helper-maven-plugin : attach-artifact doesn't copy artifact into repository

Do I need to add install-file and deploy-file to my pom after attaching an additional artifact? I believe I added my artifact correctly, but maven seems to think the artifact is already in place even thought it's not there.
After adding my additional artifact to the pom via attach-artifact I see that maven attempts to copy the file and lists the file in local repo maven-metadata-local.xml but the file doesn't get copied because it seems unchanged.
FYI - This artifact is generated by assembly-plugin and if I remove the build-helper then maven doesn't even attempt to copy the artifact.
Please let me know if you have any ideas.
Thanks
Peter
Debug Log
[INFO] Installing ./trunkProject/modules/mymodule/target/dist/added-artifact-lin64-1.0.0.59258.tar.gz
to ./m2repo/corp/prod/modules/mymodule/1.0.0-SNAPSHOT/added-artifact-1.0.0-SNAPSHOT-dist.tar.gz
[DEBUG] Skipped re-installing ./trunkProject/modules/mymodule/target/dist/aie-module-mymodule-lin64-1.0.0.59258.tar.gz
to ./m2repo/corp/prod/modules/mymodule/1.0.0-SNAPSHOT/added-artifact-1.0.0-SNAPSHOT-dist.tar.gz,
seems unchanged
Pom.xml
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>attach-distribution-artifact</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>${distTop}/${assemblyFinalName}-${real.os.full}-${prod.version}.${svn.revision}.tar.gz</file>
<type>tar.gz</type>
<classifier>dist</classifier>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
Assembly File
<assembly>
<id>dist</id>
<formats>
<format>${distCompressed.ext}</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${kitTop}</directory>
<excludes>
<exclude>**/Thumbs.db</exclude>
</excludes>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
The problem was simple order of operations. The assembly was generate during the install phase which meant the installer-plugin couldn't locate it. I don't have evidence for how this got blocked build-helper but I suspect that assemble-plugin attached, installer-failed to install and recorded the item. When build-help executed it may have been attempting to work which installer plugin already tried.
Solution
Remove build-helper
Change assembly plugin phase from install to package ensuring that the artifact exists prior to installation
set appendAssemblyId to true in pom's maven-assembly-plugin configuration

Maven SNAPSHOT jar file names not consistent using Maven Assembly in MANIFEST file

Here is the scenario:
Two Maven 3 project builds.
Build 1 has snapshot jars that get deployed to Nexus.
Build 2 has dependencies on the snapshots, referenced like 1.0.0-SNAPSHOT, that gets packaged up and zipped up using the mvn clean package assembly:single command.
The issue that we run into:
Occasionally when the assembly is being created, the MANIFEST file for the jar will sometimes say some.jar.1.0.0-SNAPSHOT and sometimes it will say some.jar.1.0.0-datetime stamp, thus causing class not defined errors.
Is there a way to prevent this naming issue in the manifest file?
--edit--
Further research has discovered the following:
"If the snapshot was resolved from a repo then it will be timestamped,
if it came from the reactor or local repo, then it will be -SNAPSHOT.
The plugin calls into the maven resolution logic so this is core maven
behavior. "
This is the exact issue that is being run into. The 2nd build manifest file always has an entry of ./lib/Framework-1.0.0-SNAPSHOT.jar where as the actual jar file name changes between ./lib/Framework-1.0.0-SNAPSHOT.jar and ./lib/Framework-1.0.0-timestamp.jar based on the quote above.
In <dependencySet> you need to set <outputFileNameMapping>${artifact.artifactId}-${artifact.baseVersion}.${artifact.extension}</outputFileNameMapping>
for example:
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>appserverB</id>
<formats>
<format>zip</format>
</formats>
<dependencySets>
<dependencySet>
<outputDirectory>/lib</outputDirectory>
<outputFileNameMapping>${artifact.artifactId}-${artifact.baseVersion}.${artifact.extension}</outputFileNameMapping>
<includes>
<include>application:logging</include>
<include>application:core</include>
<include>application:utils</include>
<include>application:appserverB</include>
</includes>
</dependencySet>
</dependencySets>
</assembly>
If you are using one of the built-in assembly descriptors you will need to replicate it for your self and add in the outputFileNameMapping entry yourself
For people who use maven-jar-plugin to create the artifact which is then packed by the maven-assembly-plugin and you still see timestamps in the classpath in artifact names, you can disable that by setting useUniqueVersions=false, as follows:
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>${project.build.finalName}.lib/</classpathPrefix>
<mainClass>com.nate.Application</mainClass>
<!-- To force the use of '-SNAPSHOT' version naming, simply disable the <useUniqueVersions> -->
<useUniqueVersions>false</useUniqueVersions>
</manifest>
<manifestEntries>
<buildTime>${maven.timestamp}</buildTime>
</manifestEntries>
</archive>
</configuration>
use <useBaseVersion>false</useBaseVersion>, when you need copy dependencies.
For example :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}</outputDirectory>
<useBaseVersion>false</useBaseVersion>
</configuration>
</execution>
</executions>
</plugin>
For those who run into this and see the answer from Stephen Connolly but still end up having exceptions, this might be due to the fact that some dependencies have classifiers in their names. Then you'll have to adapt the pattern to use the dashClassifier as an optional value:
<outputFileNameMapping>${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
This will work even if the dependecy used does not have a classifier.
See the documentation for the assembly plugin for further details.
<useBaseVersion>false</useBaseVersion> Did the trick for me. I just switched to a SNAPSHOT branch and it was including the timestamps.
Major advantage when using snapshots is one can refer to the actual date/time the snapshot was build.

maven: multi-module project assembly into single jar

I have a multi-module project and want to create a single jar containing the classes of all my modules. Inside my parent POM, I declared the following plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>bin</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
However, when running mvn assembly:assembly, only the source from the parent folder (empty) are included. How do I include the sources from my modules into the archive?
I think you are looking for the Maven Shade Plugin:
http://maven.apache.org/plugins/maven-shade-plugin/index.html
Packages up any number of dependencies into an uber package depenency. This can then be deployed to a repository.
To package classes from all modules to a single jar I did the following:
Created additional module that is used only for packing contents of all other modules to a single jar. This is usually reffered to as a assembly module. Try calling this module same as target jar file.
In pom.xml of this new module i added maven-assemby-plugin. This plugin packages all classes and puts them in single file. It uses additional configuration file (step 4.)
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>go-framework-assemby</id>
<phase>package</phase><!-- create assembly in package phase (invoke 'single' goal on assemby plugin)-->
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assemble/framework_bin.xml</descriptor>
</descriptors>
<finalName>framework</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
3.In pom.xml of this new module I also added dependencies to all other modules including parent pom. Only modules included in dependencies will be packed in target jar file.
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>fwk-bam</artifactId>
<version>${project.version}</version>
</dependency>...
4.Finally i created assembly descriptor in assembly module (file: src/main/assemble/framework_bin.xml)
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>all-jar</id>
<formats>
<format>jar</format> <!-- the result is a jar file -->
</formats>
<includeBaseDirectory>false</includeBaseDirectory> <!-- strip the module prefixes -->
<dependencySets>
<dependencySet>
<unpack>true</unpack> <!-- unpack , then repack the jars -->
<useTransitiveDependencies>false</useTransitiveDependencies> <!-- do not pull in any transitive dependencies -->
</dependencySet>
</dependencySets>
</assembly>
The predefined bin won't do the trick here. You'll have to use a custom descriptor similar to the predefined bin descriptor but that declares moduleSet to include your project modules.

Resources