Java namespace collision undetected in maven dependency

Viewed 80

What should happen in a maven project, when there are two dependencies containing same class name (with same package name, but different implementation) ?
I was expecting a build failure. But build got succeeded.

In the below example, main.launcher.MainLauncher uses mvn.dep.namespace.demo.SampleServiceImpl which is present both in dependency1 and dependency2.

Upon execution, I see SampleServiceImpl called from Dependency1 as output.

// Class from Dependency 1**
package mvn.dep.namespace.demo;

public class SampleServiceImpl {
    public String printMe() { return "SampleServiceImpl called from Dependency1"; }
}
// Class from Dependency 2**
package mvn.dep.namespace.demo;

public class SampleServiceImpl {
    public String printMe() { return "SampleServiceImpl called from Dependency2"; }
}
//Class in main project using SampleServiceImpl 
package main.launcher;

import mvn.dep.namespace.demo.SampleServiceImpl;
public class MainLauncher {
    public static void main(String[] args) {
        System.out.println(new SampleServiceImpl().printMe());
    }
}

pom.xml
<project>
   <!-- ............   ............ -->
    <dependencies>
        <dependency>
            <groupId>test.namespace.demo</groupId>
            <artifactId>dependency1</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>test.namespace.demo</groupId>
            <artifactId>dependency2</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
   <!-- ............   ............ -->
</project>



Question:

  1. Is this an expected behavior ?
  2. Are there any maven plugin to detect this?
    mvn dependency:analyze -DcheckDuplicateClasses didn't help.

Thank you!

1 Answers

I can only answer the part "Is this an expected behavior ?": Yes, it's a feature, not a bug ;-)

In Java you can have multiple implementations of the "same" class (regarding its package and class name) in your classpath. That's why it is called classpath: The first occurence "wins" and is chosen. So this can be used to overrule some implementations with others, just by placing the overruling implementation more to the front of the classpath.

In maven I would expect that in such a situation the dependency that comes first in the pom.xml is the one that "wins".

Especially for transitive dependencies this can be tricky to resolve, but you can exclude specific (transitive) dependencies.

Related