Definition: When the same fully qualified class name is provided by two or more distinct artifacts (different group IDs, different artifact IDs, or both) the classes are said to overlap.
When a class appears in more than one location in the class path, it is unpredictable which version is loaded at runtime. Indeed this can change depending on how the POMs are set up. If the overlapping classes are not identical—for example, one version has methods the other does not, or one has fixed bugs the other hasn’t—this leads to confusing, hard-to-diagnose bugs.
This can happen in several ways:
A library has published the same classes in artifacts with different group ID or artifact IDs.
A third party forks a library under their own group ID but does not repackage the classes.
A third party library copies an existing library’s packages into its own JAR file without shading the dependency. This case is particularly insidious since it may not be obvious that there’s an unexpected, undocumented version of the classes hiding inside the seemingly unrelated JAR file.
Example 1: Guava’s main artifact ID is
guava, but from versions 13.0 to 17.0,
Google also published a
guava-jdk5 artifact with classes that overlapped
guava. Build systems such as Maven and Gradle cannot deduplicate
guava because the artifact names are different.
When both artifacts appear in the classpath, users encounter
runtime errors resulting from classes and methods not being found.
Example 2: There are multiple artifacts that provide classes under
javax.servlet:servlet-api:2.5 at least). The correct choice
depends on the runtime.
javax.servletdependency should have
providedscope. Other libraries should not depend on
javax.servlet. For example, do not use constants such as
javax.servlet.http.HttpServletResponse.SC_FORBIDDENif your library might be used anywhere that is not a servlet. Define these status codes yourself or choose a different library to provide them.
In Java 9 and later overlapping classes become compile-time and runtime errors when named modules are used. It is critical, especially in Java 9 and later, to remove all but one of the artifacts that contain overlapping classes from the classpath. Generally this requires changing the POMs of multiple Maven artifacts so they no longer include any dependencies on the artifacts you need to remove from your project’s classpath.
If this isn’t possible, for instance because a dependency that imports an undesired artifact is unmaintained, then add dependency exclusions for the artifacts you wish to remove in your own project’s pom.xml.