Maven: dynamic specification of dependencies - maven-3

I have started to learn Maven and have the following question:
I would like to dynamically specify a dependency for building maven project instead of using the dependency specified in POMs - is there a way to do that?
So although I have the following dependencies specified in POM
...
<dependencies>
<dependency>
<groupId>group</groupId>
<artifactId>ProjectComponent</artifactId>
<version>1.0</version>
</dependency>
...
I would like to specify in the build command that I want to use a different version.
Is there a way to specify this?
The idea is that I want to have an integration build made in Jenkins with a dependency on the latest available snapshot of the system for a particular branch. That snapshot is not released to the maven repository yet, so I would like to fetch it in Jenkins and specify a dependency for mvn build.
Thanks!
POSSIBLE SOLUTION: What I ended up with is to use ${my.lib.version} construction and specify it with -Dmy.lib.version=1.0-SNAPSHOT" when calling to mvn. Thus I can use it for Jenkins integration builds by fetching arbitrary snapshot versions of dependencies from svn and feeding their snapshot versions to the integration build pom.

Maven may use "dynamically" specified property (ex: group.ProjectComponent.version) with the help of profiles.
<dependencies>
<dependency>
<groupId>group</groupId>
<artifactId>ProjectComponent</artifactId>
<version>${group.ProjectComponent.version}</version>
</dependency>
So if you create some profiles you may switch between them (see maven references)
Example:
<profile>
<id>stable-builds</id>
<properties>
<group.ProjectComponent.version>1.0</group.ProjectComponent.version>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>beta-builds</id>
<properties>
<group.ProjectComponent.version>2.0.Beta1</group.ProjectComponent.version>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
</profile>

What I ended up with is to use ${my.lib.version} construction and specify it with -Dmy.lib.version=1.0-SNAPSHOT" when calling to mvn. Thus I can use it for Jenkins integration builds by fetching arbitrary snapshot versions of dependencies from svn and feeding their snapshot versions to the integration build pom.

Just came across this as I was looking for something similar. In my case same application code is being reused on different stacks which means using different "drivers" for accessing data. Although drivers implement same interface they do come from different artifacts.

No you can't change the dependencies dynamically. Furthermore it does not make sense, cause you would like to have a reproducible build.

Related

Jenkins conditional steps for maven project

I use Jenkins for continuous integration.
How can I run conditional steps with Maven projects ? For free style projects I am able to set up conditional steps but this seems not available with Maven projects.
Additionally I also want to publish findbugs/pmd reports conditionally in maven projects. Again this looks possible using flexible publish plugin only for free style projects.
Any help would be highly appreciated.
-Thanks
You can add a profile in your POM and activate it only when a variable (Only setted by Jenkins for example) is present. A bit like this:
<profiles>
<!-- Jenkins by default defines a property BUILD_NUMBER which is used to
enable the profile. -->
<profile>
<id>coverage</id>
<activation>
<property>
<name>env.BUILD_NUMBER</name>
</property>
</activation>
<build>
</build>
</profile>
</profiles>
Alternatively, you can add some profiles add using them manually in the Jenkins command line:
mvn -P coverage

Using profiles in multimodule project

I have a multimodule maven project. Project layout is described below:
PARENT
|-CHILD1
|-CHILD2
Parent project has pom packaging type and declares CHILD1 and CHILD2 projects as modules. Also PARENT project declares profile dev which declares some property.
CHILD1 project has jar packaging type and "overrides" PARENT dev profile by adding some dependency(dependency on commons-collections for example).
CHILD2 project has war packaging type and has dependency on CHILD1 project. Also CHILD2 "overrides" parent dev profile by adding another dependency(dependency on commons-io for example, I mean dependency that is not related with that one in project CHILD1).
Then when I run mvn clean install -Pdev maven doesn't put commons-collections.jar(dependency that is declared in CHILD1 project) to WEB-INF/lib of CHILD2 project, but commons-io.jar is there.
So, the question is: Why does not maven put dependencies from profiles that are declared in dependent projects of target project if target project declares another set of dependencies in that profile?
Actually I have much more projects and much more dependencies that varies in different profiles. And I want to declare project specific dependencies in that project pom.xml(supposing that declaring profile in project will "override" parent profile declaration)
I am assuming that you want to be able to test locally when developing, test your changes against a staging environment and finally deploy to production.
The critical thing that you need to keep in mind is that when an artifact gets deployed to the local/remote repository, the active profiles is not part of what gets deployed, so when you add dependencies via profiles things become very dangerous as you have no way of knowing if the webapp was built with the DEV profile active or the PROD profile active, and then when that built artifact gets deployed into production you could be royally screwed over.
So the short of this is that you ensure that your artifacts are independent of deployment environment.
This means that, for example, you will pick up configuration from:
files on the classpath
system properties
jndi entries
So for example, if deploying to Tomcat, you might put a configuration.properties into $CATALINA_HOME/lib
Your webapp on startup will use getClass().getResource('/configuration.properties') to resolve the properties file and fail to start-up if the file is missing (fail-fast)
you can let your unit/integration tests use a different config by putting a test version of configuration.properties in src/test/resources.
You use the same principle for the <scope>provided</scope> style dependencies of your application. In otherwords a dependency that the container is contracted with providing should be provided by the container. So you might build the production version of tomcat/jetty for yourself using Maven also and add in the required dependencies into that assembly. This would be things like the production version uses a MySQL database, so you need to add the mysql-jdbc driver into to $CATALINA_HOME/lib. It is relatively easy to do this with the assembly plugin as you are really just repacking a zip with some bits included and others excluded.
When testing locally you will want to make use of the helper plugins' run goals such as jetty:run and tomcat:run. The solution here is that there is nothing wrong with giving these plugins dependencies via profiles because you are not affecting the dependencies of the artifact you are only affecting the plugin's classpath.
e.g.
<project>
<!-- ... some stuff .. -->
<profiles>
<profile>
<id>DEV</id>
<build>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
You can also configure system properties or classpath additions to pull in the required configuration file.
The net result of all this is that the artifact remains environment independent and you can test easily against the various environments
Hope this answers your question (even if sideways)

Using Maven API download a JAR

In a simple java program, How can I download a JAR from a Maven repository ?
The repository can be local as well as remote ? I am using Maven 3.
As noted by #amit your use of Maven-3 is not relevant. Your application is interested in accessing a JAR at runtime. It just so happens that this JAR is available at a Maven repository. Maven is a build-time tool. It cannot help you at runtime.
So if we have interpreted your question correctly, the issue is one of formulating the URL and making an HTTP request. Since you say the JAR is hosted by a Maven repository you know the format of the URL:
http://repository.url/group_id_segments_separated_with_slashes/artifact_id/version/artifact_id-version.jar
You can take advantage of this in your program if you need to access more than one JAR in this fashion.
define the necessary mapping for dependency tags in POM.xml and than provide repository information inside repository tags... for example..
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.11</version>
</dependency>
and
<repository>
<id>snapshot-repository.java.net</id>
<name>Java.net Snapshot Repository for Maven</name>
<url>https://maven.java.net/content/repositories/snapshots/</url>
<layout>default</layout>
</repository>
see more about this here

Excluding grails-plugin dependencies using the POM

Gents, ladies...
Here is the issue :
I am integrating a grails application within a complex and heterogeneous system that uses maven to build and fetch dependencies.
Fair enough, there are a few different ways to add a plugin, but I would like to have all the dependencies managed by maven, as the conflicts and scopes in the dependency trees would then be solved by maven.
This will install the hibernate plugin at validation time, and resolve its dependencies
<execution>
<id>Hibernate plugin</id>
<phase>validate</phase>
<goals>
<goal>install-plugin</goal>
</goals>
<configuration>
<pluginName>hibernate</pluginName>
<pluginVersion>${grails.version}</pluginVersion>
</configuration>
</execution>
Apparently, there is no way to specify exclusions directly in the execution configuration to prevent it from resolving its dependencies (in the dependencies.groovy script) independently.
I tried
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.11.0.GA</version>
<scope>provided</scope>
</dependency>
The dependency will not appear in the lib dir of the WEB-INF folder in the target build dir. However it is still packaged in the war archive.
Remember the aim is to use maven for all things relating to dependencies.
But anyway since it seems there is no hope of excluding it using the pom, I try using the BuildConfig with :
case Environment.PRODUCTION :
build( "org.grails.plugins:hibernate:1.3.7" ) {
excludes "javassist"
}
break
This was a last resort, and it works. Specifying the build here, will effectively override the dependencies that come from the groovy script.
So my question is, is there anyway to override these dependencies using maven ?
Obviously I verified that the dependency I was trying to scope in provided isn't included anywhere else (it is excluded from grails-gorm).
Is there an easy way to solve this ?
UPDATE :
To prevent the war from resolving jar dependencies, there is a --nojars flag, but the war goal of the grails war mojo doesn't allow the passing of args. The exec mojo does, however there is only one execution spec possible for an instance of this plugin, and no lifecycle phase can be specified for the exec mojo.
I think you were on the right track in your first attempt to mark the dependency as provided. The part that you missed is probably that you did not disable the grails dependency management. You do that by setting pom true in BuildConfig.groovy and remove all other dependencies, like this:
grails.project.dependency.resolution = {
pom true
// inherit Grails' default dependencies
inherits("global") {
}
}
Once this is done, maven will handle all depencencies.
EDIT: I just realized that this was a really old post so pom true may not have been introduced in the Grails version you were using then. I think it came in 2.2 or something like that.

Ant to Maven - multiple build targets

I have an Ant build that is currently being converted to Maven. However, the Ant build has 2 build targets - one that builds the entire app, and one that builds a JAR from some of those files (only a few). In Ant, it's easy to have multiple build targets to handle this, but I'm trying to determine the best way to handle this in Maven.
I could split the subset of files into a second project and it will have its own POM. Then the first project could depend on this one. However, since the subset of files is so small (less than 10), it seems like it might be overkill to have an entirely new project for that.
Are there other ways to handle this?
You could do this with profiles...
If you really wanted to use two separate profiles and customize the JAR plugin to include and exclude patterns of class and package names, you could easily do this by putting something like this in your POM:
<profiles>
<profile>
<id>everything</id>
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<classifier>everything</classifier>
<includes>
<include>**/*</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>only-library</id>
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<classifier>only-library</classifier>
<excludes>
<exclude>**/Main*</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Aside: If that seems like a lot of configuration, polyglot Maven's support for Groovy POMs is just about ready. It will cut the line count down considerably.
You would put this at the end of your pom.xml (withing the project element), and it adds two profiles. The first profile "everything" is really just there to demonstrate the configuration. This "everything" profile is unnecesary because it simply duplicates the behavior of the default JAR plugin jar goal execution. The second profile "only-library" excludes any class in any package that starts with the text "Main". To invoke these profiles:
mvn package -Peverything
mvn package -Ponly-library
I tested this against the sample application that ships with Chapter 6 of Maven by Example, and running either of these commands will produce a JAR file in ${basedir}/target that has a classifier. Since the JAR plugin's jar goal is bound to the package phase in the default maven lifecycle, these two profiles are going to modify the configuration for this plugin.
Or, you could do this with two JAR plugin executions...
If you need to create two JARs without using profiles. You can bind the JAR plugin's jar goal to the package lifecycle phase multiple times and use different configuration for each configured execution. If you configure two separate executions, each execution has an execution-specific configuration block so you can supply a unique identifier and include/exclude pattern for each execution.
Here is the build element you would use to add both custom JARs to the lifecycle phase "package". Doing this on a project with packaging "jar" would result in the jar goal being run three times. Once as the default lifecycle binding, and then twice for two custom, classified JARs.
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>only-library</id>
<goals><goal>jar</goal></goals>
<phase>package</phase>
<configuration>
<classifier>only-library</classifier>
<excludes>
<exclude>**/Main*</exclude>
</excludes>
</configuration>
</execution>
<execution>
<id>everything</id>
<goals><goal>jar</goal></goals>
<phase>package</phase>
<configuration>
<classifier>everything</classifier>
<includes>
<include>**/*</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
If you are not talking about including a different set of classes in each artifact, you'll want to use Maven Assemblies. If you want to know the details of assemblies, there is a chapter listed at the end of this answer from Maven: The Complete Reference. Frankly, i don't think that this particular chapter is a good introductory reference; in fact, I've had numerous reports that this chapter is nearly unreadable (and we're working to fix that). If you are looking to use assemblies, I'd recommend the Maven Assembly Plugin's documentation. In the left-hand nav menu you'll see a list of sample assembly descriptors.
Disclaimer: (Please) don't do this. If you are creating two difference JARs with two different set of classes I strongly recommend that you split the project up into two interdependent modules.
While you can do this with profiles, it is going to be easier for you to split the project into two (actually three). Longer term there are going to be challenges that you are going to face as your application scales. You will be responsible for figuring out this manual list of classes and packages to be included in each of your classified JARs.
There is minimal overhead to having a simple parent project that references two separate modules. If you look at the free Maven by Example book, we show how to make the transition between a single-module and a multi-module project. Chapters 3-5 focus on single module projects, and Chapter 6 shows you how you would combine these single module components into a larger multi-module project.
For more information:
You question involves the following topics, here are some links that will provide more details for each:
The Maven JAR Plugin: http://maven.apache.org/plugins/maven-jar-plugin/jar-mojo.html
Multi-module Maven Projects: Chapter 6 of Maven by Example and Section 3.6.2 of Maven: The Complete Reference.
The Maven Lifecycle (jar is bound to package if your packagin is "jar"): Section 3.5.2 of Maven by Example "Core Concepts" and Chapter 4 of Maven: The Complete Reference
Maven Assemblies: First, the Maven Assembly Plugin site, then Chapter 8 of Maven: The Complete Reference for some heavy (almost too heavy) details.
Your first thought is the correct one. Split the 2 pieces into 2 projects.
The maven philosophy is that each project should build one and only artifact (jar, war, whatever)
You could probably hack something together so that you only have one maven project building 2 atrifacts, but it would be a hack.
You can call ant from maven, so if you really want to do this, then I suggest you start looking at the maven ant plugin. The artifact id is "maven-antrun-plugin"
You've got 2 choices:
Profiles
Assemblies
If the subset is only a collection of resources, then I wouldn't make it a separate module.
If the project is always dependent on the subset which is packaged in a uniform way, then the subset is a good candidate to become a module.
If the subset is repackaged in multiple different "flavours", then I would define assemblies for each "flavour" and qualify the artifact names with a "classifier" see maven coordinates.
Finally, you could use profiles to determine which assemblies get produced, your default profile may only create the initial artifact "flavour" that is required during development.
A "full" profile may produce all "flavour" variants of the artifact for final deployment once development is complete.

Resources