This is similar to Exclude dependency in child pom inherited from parent pom, except that it has to do with test
vs compile
scopes.
I have a parent POM that includes the org.slf4j:slf4j-api
dependency so that all descendant projects will be using SLF4J for the logging API. Then, so that all projects can have some logging for unit tests (regardless of which SLF4J implementation they use in the main, that is non-test, part of the project), I include SLF4J Simple, but only in the test
scope:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
(I understand the view that parent POMs should not declare dependencies and only use dependency management. While I don't disagree in general, configuring tests is a different story. I don't want every single subproject to have to declare JUnit, Hamcrest, Hamcrest Optional, Mockito, Simple Logging, etc. The testing framework should be uniform across all our projects without a huge amount of ceremony just to set up a project.)
This works fine until one project Foo
wants to use Logback as the SLF4J implementation.
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.1</version>
</dependency>
That works fine for the Foo
application itself, but now for the Foo
tests, there are suddenly two competing SLF4J implementations: Logback and SLF4J simple. This presents a bindings conflict:
SLF4J: Class path contains multiple SLF4J providers.
SLF4J: Found provider [ch.qos.logback.classic.spi.LogbackServiceProvider@363ee3a2]
SLF4J: Found provider [org.slf4j.simple.SimpleServiceProvider@4690b489]
SLF4J: See https://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual provider is of type [ch.qos.logback.classic.spi.LogbackServiceProvider@363ee3a2]
I need to do one of the following:
- In the POM where I bring in the
ch.qos.logback:logback-classic
dependency, I need to exclude theorg.slf4j:slf4j-simple
from the parent POM. (This is the preferred solution.) - In the POM where I bring in the
ch.qos.logback:logback-classic
dependency, I need to specify thatch.qos.logback:logback-classic
is for all scopes except thetest
scope (so as not to conflict withorg.slf4j:slf4j-simple
).
I don't readily see how to do either of these. Any ideas?
One suggestion was to redeclare org.slf4j:slf4j-simple
with <scope>provided</scope>
. Thus pom.xml
for project Foo
would look like this:
…
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<scope>provided</scope>
</dependency>
…
Unfortunately that doesn't work. SLF4J still sees two SLF4J providers on the classpath, and is showing the message seen above. A scope of provided
simply keeps the dependency from being included transitively in other projects; it doesn't seem to remove it from the classpath of the current project.