We would like to bundle library dependencies from (Alfresco or Jackrabbit or ...) based on the customer choice. The number of dependencies actually varies based on the chosen vendor. How do we provide hooks at the maven level, so that the final product just includes the dependent jars as per customer selection.
You could achieve this by putting the needed dependencies into vendor-specific profiles in your pom:
<profiles>
<profile>
<id>Alfresco</id>
<dependencies>
...
</dependencies>
</profile>
<profile>
<id>Jackrabbit</id>
<dependencies>
...
</dependencies>
</profile>
</profiles>
Then you can activate the desired profile for your build like:
mvn -PJackrabbit install
Related
We have a Maven 2 project with lots of modules in it. Example:
<modules>
<module>common</module>
<module>foo</module>
<module>data</module>
<module>bar</module>
... more ...
</module>
Let's say the "data" module is time consuming to build and we want to exclude it when the project is build by a CI server. Currently we use two pom.xml files to achieve this. One has all modules in it and the other one has all modules except the ones which can be left out for CI. But that's pretty annoying because sometimes we forget to put a new module into both files.
Is there a solution which doesn't need two separate module lists?
With Maven 3.2.1, you can now use -pl !<module_name>,!<module_name> to exclude certain modules from the reactor build.
See this feature request: https://issues.apache.org/jira/browse/MNG-5230
The easiest might be to use profiles like this:
<project>
...
<modules>
<module>common</module>
<module>foo</module>
<module>bar</module>
<modules>
...
<profiles>
<profile>
<id>expensive-modules-to-build</id>
<modules>
<module>data</module>
</modules>
</profile>
</profiles>
</project>
You should then check out ways you can activate profiles
The projects to build can also be specified on the mvn command line. This would remove the need for a separate pom, but instead you would have to change the CI configuration everytime there is a new module.
-pl,--projects <arg> Comma-delimited list of specified
reactor projects to build instead
of all projects. A project can be
specified by [groupId]:artifactId
or by its relative path.
Maybe a combination of this flag and --also-make-dependents or --also-make would reduce this maintenance burden again.
-am,--also-make If project list is specified, also
build projects required by the
list
-amd,--also-make-dependents If project list is specified, also
build projects that depend on
projects on the list
I assume you want the default build to always build everything, regardless of speed, so that new developers can get started quickly without having to understand lots about the POM. You can use profiles like this:
<modules>
<module>common</module>
<module>foo</module>
<module>bar</module>
</modules>
...
<profiles>
<profile>
<id>expensive-modules-to-build</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<modules>
<module>data</module>
</modules>
</profile>
</profiles>
</project>
The problem with this is that if a developer specifies another profile on the command line, then the expensive-modules-to-build isn't included (unless the developer also specifies it). This makes it complicated to remember which profiles need to be included.
Here is a hacky way around that. Both profiles are always included, because the pom.xml file always exists. So to exclude the expensive modules, you can use -P!full-build on the command line.
<profiles>
<profile>
<id>full-build</id>
<activation>
<file>
<exists>pom.xml</exists>
</file>
</activation>
<modules>
<module>data</module>
</modules>
</profile>
<profile>
<id>short-build</id>
<activation>
<file>
<exists>pom.xml</exists>
</file>
</activation>
<modules>
<module>common</module>
<module>foo</module>
<module>bar</module>
</modules>
</profile>
</profiles>
Another idea: Reactor modules can be nested, so it should be possible to group your fast and slow-building modules into separate poms and then add another aggregator pom containing these two as modules. Your CI Server could then only reference the pom containing the fast building modules.
<artifactId>fast</artifactId>
<modules>
<module>fast-a</module>
<module>fast-b</module>
<module>fast-c</module>
</module>
<artifactId>all</artifactId>
<modules>
<module>fast</module>
<module>slow</module>
</module>
You could be to use maven profiles. In our build environment, we created a profile quick that disables many plugins and test execution.
This is done by
<profile>
<id>quick</id>
<properties>
<skipTests>true</skipTests>
<!-- others... -->
</properties>
<build>
<plugins>
<!-- configuration... -->
</plugins>
</build>
</profile>
And then we invoke maven the following way
mvn groupId:artifactId:goal -P quick
You could maybe disable compilation and other standard plugins in the pom of your module to speed it up.
Not exactly the answer these folks were asking for. My situation was I wanted to deploy only the parent pom. I'm using the spring-boot-thin-layout in a child module. This requires the parent module be deployed into artifactory. I added the following into my project. It enables skipping of install and/or deploy phase.
In my parent pom:
<properties>
<disable.install>true</disable.install>
<disable.deploy>true</disable.deploy>
<enable.deployAtEnd>true</enable.deployAtEnd>
</properties>
<profiles>
<profile>
<id>deploy-parent</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<disable.install>true</disable.install>
<disable.deploy>true</disable.deploy>
<deployAtEnd>${enable.deployAtEnd}</deployAtEnd>
</properties>
<build>
<finalName>${project.version}</finalName>
</build>
</profile>
</profiles>
And the in my child pom(s) or any module you don't want deployed with parent:
<properties>
<maven.install.skip>${disable.install}</maven.install.skip>
<maven.deploy.skip>${disable.deploy}</maven.deploy.skip>
<deployAtEnd>${enable.deployAtEnd}</deployAtEnd>
</properties>
So effectively when I run mvn deploy on the parent pom, it will compile all the modules, not run install on anything, and then at the end deploy any module not having <maven.deploy.skip>${disable.deploy}</maven.deploy.skip> in it's properties. So in my case only deploying the parent.
I have a multi-module project, and I am using profiles in the parent pom , which have specific dependencies mentioned in them.
The issue here is that, if in a child pom , I am overriding the dependency element, and mentioning one of the dependencies in the parent pom (which is declared in a profile in parent pom) , the version of that specific dependency needs to be mentioned again.
E.g
Parent pom
<dependencies>
<dependency>
<groupId>com.mycode.apps</groupId>
<artifactId>jobs</artifactId>
<version>4</version>
</dependency>
</dependencies>
<profiles>
<profile>
<id>common-dependencies</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>com.mycode.apps</groupId>
<artifactId>dao</artifactId>
<version>4</version>
</dependency>
</dependencies>
</profile>
</profiles>
Now in child pom.xml
<dependencies>
<!--this one doesnt need a version specified -->
<dependency>
<groupId>com.mycode.apps</groupId>
<artifactId>jobs</artifactId>
</dependency>
<!--this one makes maven throw an error(if version is not specified) while compilation -->
<dependency>
<groupId>com.mycode.apps</groupId>
<artifactId>dao</artifactId>
</dependency>
</dependencies>
Any idea what might be wrong and how can I fix this??
NOTE: The profile is marked as activeByDefault
For this kind of requirments you the dependencyManagement which is exactly for such cases. Or take look into the Sonatype Book.
This case shouldn't be handled by profiles.
Suppose I have a module A:jar, whose runtime and compilation set of dependencies depends on the JDK version. In my example, I have a pre-jdk6-profile for JAXB API: prior to JDK 1.6.0 I need to include jaxb-api-nnn.jar as a compile dependency. This profile is placed to A.pom.
I also have module B:war, which depends on A:jar. I want to be able to activate this profile on a build server to build the JDK 1.5.x deliverable. When I execute Maven with a given profile activated, I get the message:
mvn -Ppre-jdk6-profile -o install
[WARNING]
Profile with id: 'pre-jdk6-profile' has not been activated.
and jaxb-api-nnn.jar is missing in resulting B.war. However if I activate this profile when building from the parent pom.xml, everything is OK. That means the profiles are not inherited from dependencies, and the parent multi-module pom.xml was able to build everything correctly because it seems like all profiles are merged in reactor.
Shifting the profile to parent pom makes things worse, as the dependencies are applied to all other projects (e.g. to C:ear). Are there nice solutions for this task, namely, if any module A depends on module B, then all compile and runtime dependencies which are activated by a profile, are correctly handled?
The profile in project A:jar follows:
<project ...>
<artifactId>A</artifactId>
<packaging>jar</packaging>
...
<parent>
<artifactId>P</artifactId>
...
</parent>
<profiles>
<profile>
<id>pre-jdk6-profile</id>
<activation>
<jdk>(,1.6.0)</jdk>
</activation>
<dependencies>
<dependency>
<groupId>javax.xml.ws</groupId>
<artifactId>jaxws-api</artifactId>
</dependency>
</dependencies>
</profile>
</profiles>
...
</project>
a) In a multi-module build, you should always build from the top pom, never from an individual module. If you want to build only one module, use advanced reactor options (see mvn --help) like this:
mvn -pl mymodule
b) Define and activate the profile in the parent pom, but add the configuration in the child pom.
parent pom.xml
<profiles>
<profile>
<id>pre-jdk-6</id>
<activation>
<jdk>(,1.6.0)</jdk>
</activation>
</profile>
</profiles>
child pom.xml
<profiles>
<profile>
<id>pre-jdk-6</id>
<dependencies>
<dependency>
<groupId>javax.xml.ws</groupId>
<artifactId>jaxws-api</artifactId>
</dependency>
</dependencies>
</profile>
</profiles>
Several notes way after the fact:
When you use -P profName, it activates a profile named 'profName'
After that, it disables all profiles that have an <activation> tag for them. It doesn't matter whether they are activated by the java version, as in the example, or by default or env value or anything.
That means the -P causes any otherwise activated profile to become deactivated.
Solution: Either use <activation><jdk>...</jdk></activation> or use -P but do not use both.
how to exclude a dependency from war but using it till testing or development
As the others suggested, scope=provided or scope=test is the way to go.
<scope>provided</scope> implies that the library will be present in the target system and doesn't need to be deployed. (Or in some cases like log4j must not be deployed, because otherwise classloader issues will result)
<scope>test</scope> suggests that the dependency is only needed for test code (and hence will not be needed or provided on the target system)
Here is the relevant documentation:
Introduction to the Dependency Mechanism
On a related note: A different use case is that where you use different databases on different servers. You can use profiles to deploy the correct drivers:
<profiles>
<profile>
<id>testserver</id>
<dependencies>
<dependency>
... (database driver a)
</dependency>
</dependencies>
</profile>
<profile>
<id>productionserver</id>
<dependencies>
<dependency>
... (database driver b)
</dependency>
</dependencies>
</profile>
<profile>
<id>localdevelopment</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<dependency>
... (database driver c)
</dependency>
</dependencies>
</profile>
</profiles>
That way, if you just call mvn install, driver c will be deployed, whereas mvn install -Ptestserver and mvn install -Pproductionserver will include drivers a or b, respectively.
There is an option to specify scope with in the dependency tag. You can specify scope as test and it won't be included into your war but will only be used for tests.
You do it with <scope>provided</scope> tag.
<dependency>
<groupId>org.livetribe</groupId>
<artifactId>livetribe-jsr223</artifactId>
<version>2.0.6</version>
<scope>provided</scope>
</dependency>
I have a maven module which has some dependencies. In a certain profile, I want to exclude some of those dependencies (to be exact, all dependencies with a certain group id). They however need to be present in all other profiles. Is there a way to specify exclusions from the dependencies for a profile?
To my knowledge, no, you can't deactivate dependencies (you can exclude transitive dependencies but this is not what you are asking for) and yes, what you are currently doing with the POM (manually editing it) is wrong.
So, instead of removing dependencies, you should put them in a profile and either:
Option #1: use the profile when required or
Option #2: mark the profile as activated by default or put it in the list of active profiles and deactivate it when required.
A third option would be (not profile based):
Option #3: separate things in two separated modules (as you have separated concerns) and use inheritance.
Instead of excluding dependencies in a profile, you can set them as provided in it. This doesn't require any overly complex configuration and will exclude the dependencies you don't want from the final build.
In the desired profile, add a dependencies section, copy the declaration of the ones you want to exclude and scope them as provided.
For example, let say you want to exclude slf4j-log4j12:
<profiles>
<!-- Other profiles -->
<profile>
<id>no-slf4j-log4j12</id>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
<!-- Other profiles -->
</profiles>
One way that occurs to me is to have the dependencies in a separate pom. You can then add an <exclusions> section via the profile.
<dependencies>
<dependency>
<groupId>my.company.dependencies</groupId>
<artifactId>my-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>pom</type>
</dependency>
</dependencies>
<profile>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>exclude-deps</name>
</property>
</activation>
<dependencies>
<dependency>
<groupId>my.company.dependencies</groupId>
<artifactId>my-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>my.company</groupId>
<artifactId>bad-dep-1</artifactId>
</exclusion>
<exclusion>
<groupId>my.company</groupId>
<artifactId>bad-dep-2</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</profile>
I don't think it is possible to exclude direct dependencies either (at least, nothing is mentioned here).
The best thing you can do is to enclose the desired dependencies for each case into different profiles (as suggested already), but, you'll need to create two "mutually exclusive" profiles with the one of them "active by default". The most reliable way to achieve this is by using a parameter for your profile activation e.g.
<profiles>
<profile>
<id>default-profile</id>
<activation>
<property><name>!exclude</name></property>
</activation>
<dependencies>
dependency-A
dependency-B
...
</dependencies>
</profile>
<profile>
<id>exclude-profile</id>
<activation>
<property><name>exclude</name></property>
</activation>
<!-- exclude/replace dependencies here -->
</profile>
</profiles>
Then using "mvn [goal]" will use profile "default-profile", but "mvn [goal] -Dexclude" will use profile "exclude-profile".
Note that using 'activeByDefault' instead of a parameter for your "default" profile might work in some cases but it also might lead to unexpected behavior. The problem is that 'activeByDefault' makes a profile active as long as there is no other active profile in any other module of a multi-module build.
maven is a tool, we can hack it.
maven runs fine if you have the same artifact + version defined as dependency twice.
define a profile that eliminates an artifact + version by changing it to another package we already have.
For example, in the pom.xml:
... other pom stuff ...
<properties>
<artifact1>artifact1</artifact1>
<artifact2>artifact2</artifact2>
<artifact1.version>0.4</artifact1.version>
<artifact2.version>0.5</artifact2.version>
</properties>
<profile>
<id>remove-artifact2</id>
<properties>
<artifact1>artifact1</artifact1>
<artifact2>artifact1</artifact2>
<artifact1.version>0.4</artifact1.version>
<artifact2.version>0.4</artifact2.version>
</properties>
</profile>
Now if you install this pom.xml without the profile, artifact1:0.4 and artifact2:0.5 will be the dependency.
But if you install this pom.xml with the profile mvn -P remove-artifact2
The result pom.xml contains only artifact1:0.4
This comes quite handy during api migration where artifact are renamed and versions are not compatible.
Bit dirty but lightweight solution is to use <scope>import</scope>.
Unlike the other scopes you could use this:
will disable compile-time and runtime dependecies; unlike provided or runtime which disables only one at a time
won't mess up your test scope
you don't need to specify path to some dummy jar as would system scope require
Nothing gets imported as long as you use this hack outside dependencyManagement.