Different dependencies for different build profiles - java

Is it possible to have a different set of dependencies in a maven pom.xml file for different profiles?
e.g.
mvn -P debug
mvn -P release
I'd like to pick up a different dependency jar file in one profile that has the same class names and different implementations of the same interfaces.

To quote the Maven documentation on this:
A profile element contains both an optional activation (a profile trigger) and the set of changes to be made to the POM if that profile has been activated. For example, a project built for a test environment may point to a different database than that of the final deployment. Or dependencies may be pulled from different repositories based upon the JDK version used.
(Emphasis is mine)
Just put the dependency for the release profile inside the profile declaration itself and do the same for debug.
<profiles>
<profile>
<id>debug</id>
…
<dependencies>
<dependency>…</dependency>
</dependencies>
…
</profile>
<profile>
<id>release</id>
…
<dependencies>
<dependency>…</dependency>
</dependencies>
…
</profile>
</profiles>

Your groupId, artifactId should be tokenized in your profiles as properties and you can move your dependencies to the generic section.

Related

How to have maven resolve a dependency of a dependency which was created by a non-default profile for some classifier?

Given a library which has different dependencies depending on a profile, say for example
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<envClassifier>cuda-10.1</envClassifier>
</properties>
<dependencies>
<dependency>
<groupId>org.jcuda</groupId>
<artifactId>jcuda</artifactId>
<version>10.1.0</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>cuda-10.0</id>
<properties>
<envClassifier>cuda-10.0</envClassifier>
</properties>
<dependencies>
<dependency>
<groupId>org.jcuda</groupId>
<artifactId>jcuda</artifactId>
<version>10.0.0</version>
</dependency>
</dependencies>
</profile>
I am creating artefacts with different classifiers, say for example
library-1.0.0-cuda-10.0
and
library-1.0.0-cuda-10.1
(here cuda-10.0 and cuda-10.1 are the classifiers for the artefact library-1.0.0).
If another project references this library, say for example as
<dependency>
<groupId>net.finmath</groupId>
<artifactId>library</artifactId>
<version>1.0.0</version>
<classifier>cuda-10.0</classifier>
</dependency>
then the correct artefact is pulled (here library-1.0.0-cuda-10.0.jar) but the dependency tree (via mvn dependency:tree) shows the wrong dependencies of the dependency. In this example it shows jcuda-10.1.0 and not juda-10.0.0.
This issue is due to an artefact having a single pom.xml for all classifiers (and the default profile kicks in).
Question 1: Can you have dedicated pom.xml in the repositories for different classifiers, to reflect the correct dependencies?
Apparently the issue cannot be resolved by setting a profile (-P parameter) on the outer project, because profile selectors are not passed to the poms of the dependencies. It looks as if profiles do not walk down the dependency tree.
Question 2: Is there a way to pass a profile selector to a pom of a dependency to select the right dependencies of the dependency?
I found two options to resolve the problem, but I am not very happy with them.
The first one would be to not have a default profile with a dependency in the pom of the library. In that case the user of the library (here library-1.0.0) has to specify the correct classifier and the correct downstream dependencies. This appears to be cumbersome. Also note that in this case the build of the library would fail without specification of the profile.
It is possible to use the profile to alter the name (or version) of the artefact. Since each version or artefact comes with its own pom, this allows to specify profile specific dependencies to be resolved.
However, I believe there should be a better solution, because otherwise it looks as if the specification of dependencies in profiles makes no sense for artefacts which are libraries, that is, which are themselves dependencies of another projects.
Question 3: What is the Maven way to resolve this issue?
PS: The question arose in this project: http://finmath.net/finmath-lib-cuda-extensions/
I found a lightweight solution for the problem.
You may activate a profile though a property.
Properties may not be passed from a pom to the poms of it's dependencies, but a property which is set on the command line acts on both poms.
Hence, instead of using a profile on the command line, use a property and activate the corresponding profiles in your project's pom and the library's pom.
So in the above example, the (outer) project (which references the library) has a profile
<profile>
<id>cudaversion</id>
<activation>
<property>
<name>cuda.version</name>
</property>
</activation>
<properties>
<finmath-cuda.classifier>cuda-${cuda.version}</finmath-cuda.classifier>
</properties>
</profile>
which sets the classifier of its dependency, that is this project has a dependency to library-1.0.0
<dependency>
<groupId>net.finmath</groupId>
<artifactId>library</artifactId>
<version>1.0.0</version>
<classifier>${finmath-cuda.classifier}</classifier>
</dependency>
And the pom of library-1.0.0 has a profile which is activated by the same property as in
<profile>
<id>cuda-10.0</id>
<activation>
<property>
<name>cuda.version</name>
<value>10.0</value>
</property>
</activation>
<properties>
<envClassifier>cuda-10.0</envClassifier>
</properties>
<dependencies>
<dependency>
<groupId>org.jcuda</groupId>
<artifactId>jcuda</artifactId>
<version>10.0.0</version>
</dependency>
</dependencies>
</profile>
The outer project is then build with mvn -Dcuda.version=10.0 to activate both profiles.

Maven project with "war" packaging: how to create JAR with maven-jar-plugin? [duplicate]

I have a project which I compile with maven. I have different profiles declared in pom.xml.
For some of these profiles, I prefer building a war, and for other profiles I prefer a jar. I use to manually edit the pom.xml file and change packaging variable to either
<packaging>war</packaging>
or
<packaging>jar</packaging>
before doing a
$ mvn clean package -Pchosenprofile
How can I tell mvn the packaging corresponding to each profile so I don't need to edit pom.xml?
If you want to use profile you can use something like:
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
..
<packaging>${packaging.type}</packaging>
<profiles>
<profile>
<id>webapp</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<packaging.type>war</packaging.type>
</properties>
</profile>
<profile>
<id>batch</id>
<properties>
<packaging.type>jar</packaging.type>
</properties>
</profile>
</profiles>
</project>
Have you looked at the attachClasses configuration setting of the war plugin? This simple setting would let you build both a war and a jar (by default with the classifier "classes") in a single maven execution.
I don't think you can.
Two alternatives I can think of:
have two separate modules for packaging, and call one of those depending on profile
have your module in war and tweak the lifecycle (include/exclude build steps) depending on profile to produce your jar or your war
I like the second approach better - a build server would probably build both, and a developer would use the proper profiles/settings to skip the unwanted type.

Maven dependency version in profile section when defined in dependencyManagement

We have several of our project modules defined in our master pom within the dependencyManagement section so that they can be used in child poms but maintain a consistent version. This is pretty standard, I think.
Now, within a profiles section of a child POM I would like to add a dependency and not define the version as I know this dependency definition exists in the Parent POM dependencyManagement section.
e.g.
...
<profiles>
<profile>
<id>DEV_PC</id>
<dependencies>
<dependency>
<groupId>com.our.project</groupId>
<artifactId>module1</artifactId>
</dependency>
</dependencies>
</profile>
<profile>
...
I am seeing some odd behavior in the build and wonder if it this approach is allowed or do you always have to define the version of a dependency in a profile section?
To answer my own question:
You can use dependencies that are defined in a dependencyManagement section without a version in the profiles section as shown above in my example.
I have added a comment below explaining the odd behavior I had seen.

Maven Profile in different dependencies

I have a Maven module with two different database profiles.
<profile>
<id>db-localhost-oracle</id>
<dependencies>
<dependency>
<groupId>ojdbc6</groupId>
<artifactId>ojdbc6</artifactId>
</dependency>
</dependencies>
<properties>
<db.driver>oracle.jdbc.driver.OracleDriver</db.driver>
<db.dialect>no.jbv.sergej.util.FixedOracle10gDialect</db.dialect>
<db.url>jdbc:oracle:thin:#//localhost:1521/xe</db.url>
<db.hbm2ddl>update</db.hbm2ddl>
</properties>
</profile>
<profile>
<id>db-localhost-mysql</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<properties>
<db.driver>com.mysql.jdbc.Driver</db.driver>
<db.dialect>org.hibernate.dialect.MySQL5Dialect</db.dialect>
<db.url>jdbc:mysql://localhost/${mysql.schema}</db.url>
<db.hbm2ddl>update</db.hbm2ddl>
</properties>
</profile>
When is run maven install with "db-localhost-mysql" it includes the "mysql-connector-java" jar file in lib directory. Now I do clean install with "db-localhost-oracle" and it includes the both "mysql-connector-java" and "ojdbc6" jars in the lib directory.
How can I make it like, if I build with one profile maven automatically remove the jars for other profile?
Your problem does not match what should happen in practice. Your profile definition sounds about right to me:
mvn clean install will enable the db-localhost-mysql (as it is marked as to be activated by default) and it will add mysql-connector-java. The same will happen if you run mvn clean install -Pdb-localhost-mysql
mvn clean install -Pdb-localhost-oracle will add the ojdbc6 driver. The mysql profile will not be enabled (as it is triggered only if no profile is explicitly active).
That does not mean your current dependency hierarchy hasn't already one of those jars. It might come as a transitive dependency. To isolate this case and know which project needs to be fixed run mvn dependency:tree -Pdb-localhost-oracle to look at your dependencies hierarchy when the mysql profile is not enabled.
I assume you download your downloaded dependencies using maven-dependency-plugin somewhere outside your target dir (${basedir}/lib).
If that is the case, you would need to include your lib dir inside your clean definition (see http://maven.apache.org/plugins/maven-clean-plugin/examples/delete_additional_files.html):
<build>
[...]
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.5</version>
<configuration>
<filesets>
<fileset>
<directory>lib</directory>
</fileset>
</filesets>
</configuration>
</plugin>
[...]
</build>
However: Please consider doing it differently:
do not have your regular build change anything outside the target directory, if possible (which would have prevented your problem in first place), instead download to something like target/lib
Please do not use profiles to change the outcome of your build. This is dangerous. (see http://www.blackbuild.com/how-to-really-use-maven-profiles-without-endangering-your-karma/ for an extended explanation)
If you want different outcame consider Maven Assemblies.

Maven profiles - build without child projects

I have a maven project with multiple child projects. I also have a maven dbunit plugin which I invoke from command line like this:
mvn dbunit:operation -P test -pl .
-P is a profile switch where all necessary properties are stored (like db url, etc.)
I.e.:
<profile>
<id>test</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<driver>org.postgresql.Driver</driver>
<url>jdbc:postgresql://localhost:5432/db</url>
<username>ers</username>
<password>ers</password>
<useQualifiedTableNames>true</useQualifiedTableNames>
<dataTypeFactoryName>org.dbunit.ext.postgresql.PostgresqlDataTypeFactory</dataTypeFactoryName>
<format>flat</format>
<type>INSERT</type>
<src>${basedir}/some_path/test.xml</src>
</properties>
</profile>
The problem I'm having is that I need to specify -pl . parameter to build only one project (root/parent project) so that the dbunit data is loaded only once. Is it possible to specify some property directly in the profile, so only 1 project is being build? I tried <pl>my_project</pl> and <project>... - but no luck. Thanks!
Yes. The <modules> element can be specified in a profile. So the solution would be to move the DBUnit setup code in a module and then:
<profile>
<id>test</id>
<modules>
<module>db-unit-setup<module>
</modules>
</profile>
If you activate this profile with -P test, only the single module db-unit-setup and the parent POM will be built. But since the parent POM is now an empty project (it's just a POM without any code), that shouldn't hurt.

Categories