0

The specific use case is regarding third-party libraries that depend on the older log4j 1.x like log4j:log4j:1.2.17 which is EOL'd some years ago. Apache provides the newer log4j 2.x library like org.apache.logging.log4j:log4j-1.2-api:2.13.3. I understand I can use excludeDependencies to omit log4j:log4j or dependencyOverrides to change the version of a dependency. Since org.apache.logging.log4j:log4j-1.2-api:2.13.3 is provided to implement the log4j 1.x API, I'm hoping I can write a rule "like":

SBT: if a transitive dependency is found for log4j:log4j:1.2.17, instead bring in org.apache.logging.log4j:log4j-1.2-api:2.13.3

bvesco
  • 361
  • 4
  • 8

1 Answers1

1

Technically, you can do it, and in several ways. For instance, You can add to your sbt:

libraryDependencies ++= Seq(
  "org.apache" %% "dependecy-name" % "version" exclude("org.slf4j","slf4j-log4j12")
  "org.slf4j" %% "slf4j-log4j12" % "other-version"
)

This lines will tell SBT to not add the slf4j-log4j12 as it is required by dependecy-name, and later on it will be acquired in the other-version.

Having said that, we need to understand the risk of doing so. Usually, when a library adds a dependency, it uses its functionality in a certain version. When you decide to override the version of that dependency, it is possible that your code won't compile, or worse, it will run and will cause different results, then what you expect. In case you are sure that the two versions have the same functionality, you can do that.

Update: In order to remove the dependency you can add to your build.sbt:

libraryDependencies ~= { _ map {
  case m if m.organization.contains("org") =>
    m.exclude("log4j", "log4j")
  case f => f
}}

That will go over all of your dependencies, and each one that contains org in its organization, will exclude log4j. Please note that this will take effect only on the top level dependencies, in your libraryDependencies.

Tomer Shetah
  • 8,413
  • 7
  • 27
  • 35
  • Thank you for your ideas. I may be missing something or you may be missing a nuance of the question. The key part is to find a way to exclude/include conditionally. For the second half where you bring up risk, this will be related to another nuance of the question. My specific application is for the end-of-life Log4j 1.x which is supplanted by the Log4j 2.x adapter for 1.x functionality. So this is a special case where compatibility is implicit for this override. Thoughts or ideas? – bvesco Aug 06 '20 at 16:45
  • Nice update. I learned from it. I'm not quite there yet. In my experimentation, it seems to filter on the direct dependencies and not the transitive dependencies. My given use case is deep a transitive dependency that has a dependency on the deprecated log4j 1.x API. I'll add that my sbt project has many modules and I'm hoping to set up a rule that will exclude/replace on the condition that some deep transitive dependency tries to bring in the 1.x jar. What I'm doing currently is exclude 1.x from _all_ modules and import 2.x shim to all modules whether they needed it or not. – bvesco Aug 06 '20 at 18:27
  • That is exactly what I stated. It works on the direct dependencies. But with you call `m.exclude("log4j", "log4j")` on a direct dependency, it will not fetch it. You can control which modules should apply that logic by editing the `if` statement I added. In my experiment, after adding this change, log4j:log4j was not in the dependency tree I was working on. – Tomer Shetah Aug 06 '20 at 18:33
  • In addition, why would you like to exclude a dependency from the transitive dependency? Let's say you have a dependency `a`, which depends on `b` and `c`. You want to exclude dependency `d` only from `b`? You might get it back from `c`. What am I missing here? If you want to exclude it, you want to exclude it globally. The only reason I see you need to put it under a condition, is when using different dependencies on different scala versions. – Tomer Shetah Aug 06 '20 at 18:41
  • What I'm looking for is more like, "if A is a transitive dependency at any depth, exclude A and include B." I'm more and more convinced this is not possible. I'm hoping someone else has a bright idea. – bvesco Aug 07 '20 at 01:01
  • You can also try the answer at: https://stackoverflow.com/a/36501752/2359227 – Tomer Shetah Aug 07 '20 at 10:51
  • I appreciate all the attempts to help. I'm aware of dependencyOverrides but it's a 1:1 override. As in, I can use it to override log4j with a newer log4j but can't use it to override log4j with log4jAdapter. I think I have to accept that what I want is not possible and live with globally excluding log4j and bringing log4jAdapter into every module whether it needs it or not. Again, thank you. – bvesco Aug 07 '20 at 15:27