Reputation: 1017
I have 3 jars namely jar1,jar2,jar3.
In jar1 there is some code which reads the file from the classpath. However the file won't be present in classpath of jar1. Instead, jar2 will be plugged in as dependency of jar1 and jar2 classpath would contain that file.
I have jar3 which will also contain the same file in its classpath but I would declare the scope as test
for jar3 in pom.xml
of jar1.
Now when the test cases are executed how can we tell maven to always take the file from jar3 (scope as test) classpath although jar2 is given as main dependency (scope not as test)?
Is this possible through maven profiles? If yes how can we specify it? Or can we use maven-resources-plugin to copy the file during test scope?
How exactly does classpath will be set if the same files are present in multiple jars given as dependency?
Sample jar1 pom.xml
<dependencies>
<dependency>
<groupId>com.test</groupId>
<artifactId>jar2</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.test</groupId>
<artifactId>jar3</artifactId>
<version>0.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
</dependencies>
Both jar2 and jar3 has the resource file.
Question: Which will be picked up and why?
Upvotes: 1
Views: 610
Reputation: 27812
If you dependencies are at the same level in the dependency tree, the order of declaration in your pom will win, as per Maven Dependency Mediation doc:
Note that if two dependency versions are at the same depth in the dependency tree, until Maven 2.0.8 it was not defined which one would win, but since Maven 2.0.9 it's the order in the declaration that counts: the first declaration wins
So in your case the two dependencies are at the same level in the dependency tree (first level, declared in the POM) and compile
scope would be present whenever test
scope would be, as such jar2
would win because you declared it first in your POM (according to the snipped you posted).
If you want the file to be loaded always from jar3
but only during tests, simply declare jar3
first in your dependencies. It will not impact the final deliverable (being in test
scope) but it will define the order to the classpath for testing and as such giving you the expected scenario. You don't need Maven profiles for that.
A simple test case to verify it:
Let's define a property file.properties
into src\main\resources
of a Maven project. The file would look like the following for project resource-provider
(artifactId):
property=from-resource-provider
And as following for project resource-provider2
(artifactId):
property=from-resource-provider2
Note: the same file name into two different projects with different content.
Then in a consumer project (resource-consumer
) we could have the following sample JUnit test case:
public class MainTest {
@Test
public void checkClassPath() {
InputStream is = MainTest.class.getResourceAsStream("/file.properties");
Scanner s = new Scanner(is);
System.out.println(s.nextLine());
}
}
For the following dependencies into resource-consumer
:
<dependencies>
<dependency>
<groupId>com.sample</groupId>
<artifactId>resource-provider2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sample</groupId>
<artifactId>resource-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
Output of test execution would be:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.sample.MainTest
property=from-resource-provider2
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.051 sec
So, the first dependency declared, resource-provider2
, won (note the scope, test
).
Changing the dependencies order to:
<dependencies>
<dependency>
<groupId>com.sample</groupId>
<artifactId>resource-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.sample</groupId>
<artifactId>resource-provider2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
Would instead give the following output:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.sample.MainTest
property=from-resource-provider
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.07 sec
Note: this time resource-provider
won, because it was declared first and because compile
scope is also part of test
scope, while the contrary is not true.
Upvotes: 1