26203

How java/maven resolves dependency conflicts at run time

Sorry for my newbie question.

Supposedly I have a package A which declares B, C as its dependencies in its maven files for example. B, C use two different versions of log4j for logging. I have a couple of questions:

<ol> <li>If I use maven, and declare B, C as A's dependencies. When maven pull in artifact (.jar) of B,C from mavencentral repo. Do B,C jar files contain log4j class files or just contain only their own compiled files (B,C own source, not dependency).</li> <li>If I understand correctly, when build happens, at the end, there will only be one log4j class file in the build (even if B, C use different versions of log4j). Which version of log4j to be selected to build here? Does it mean that I need to declare log4j as A dependency as well (in A's maven build file) - and that version will be selected version to build.</li> <li>B, C might use totally different log4j versions. There API might be completely different. It should cause problem at run time? But in reality, it's very rare? Why so? </li> </ol>

Thanks.

Answer1:

<ol> <li>

jar files usually do not contain their dependencies. There is a way to do this called fat jar. What is a fat JAR? but let's assume you are using regular jar dependencies. The jars will only declare their dependencies in their own pom.xml. So for your example, B and C will contain only their own compiled source code.

</li> <li>

It really depends on how you pack the files. In general, if you only generate a simple jar, it will not contain the dependencies, and it is the responsibility of the runner to supply the correct dependencies. In case of a war, for example, maven will throw in all dependencies. Another way as mentioned before is fat jar. One more common way is to zip all the dependencies and supply them separately.

</li> <li>

I do not know why you have not encountered a conflict before, I have, with many other libraries, I do not remember a case with log4j though. One way to handle these kind of conflicts, as a library maintainer, is when you make a non backward compatible change, to change the package name, this way the user can safely have multiple versions in the classpath (which should be avoided anyway).

</li> </ol>

Maven has a way to avoid these kind of conflict, it will give priority to the closest defined dependency version. For example, if you have version a declared in A and version b in B, then the effective version will be A.

Also, there are some other mechanisms like dependency management. You can look here: https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html

This topic is a very serious and may cause a lot of hard to detect production errors. Hope this helps...

Answer2:

<ol> <li>They should only contain their own classes. Not the classes of their dependencies. You can just open the jar files and see by yourself. Jar files are just zip files.</li> <li>Maven will solve the conflict by picking the version that is the closest to the root of the dependency tree. If both versions are at the same depth in the dependency tree, then the first one is picked (IIRC). If A itself depends on log4j, or if you want a specific version to be used at runtime, you should specify log4j as a direct dependency of A, with the version you want. Or at least specify it in the dependencyManagement section of your build.</li> <li>Because libraries as popular as Log4J strive to have a very stable API, which thus doesn't break code compiled against older versions of the library.</li> </ol>

Answer3:

<ol> <li>An artefact will normally not contain its dependencies (however there are packaging options that do).</li> <li>Maven will determine only one version using some rules (that I don't remember in detail). If you have to override this for some reason you can put a dependency management section into the POM.</li> <li>Yes this can cause problems. They can only be avoided by being careful when making changes to the public API.</li> </ol>

Answer4:

<ol> <li>

If log4j is specified as a dependency of B and C and you do not use special plugins that create uber-jars/fat-jars, both B and C will not contain log4j class files.

</li> <li>

One dependency with same coordinates (groupId, artifactId). As someone here already mentioned, version is usually picked by shortest path to root. So if you want to use a specific log4j-version you just can specify it in your pom.

</li> <li>

If you use log4j the standard way, i.e. by just specifying the config files, both versions (log4j and log4j2) can usually coexist due to the fact they are using different packages and different configuration files. Just check the migration site of log4j: Migration from log4j to log4j2

</li> </ol>

Recommend

  • Covariant return type with non-pointer/reference return type
  • Extending enums
  • Is a collocated join (a-la-netezza) theoretically possible in hive?
  • Possible F# type inference limitation
  • How to run a single row of a Cucumber scenario outline example table in RubyMine?
  • What is an Artifact?
  • How to modify search result page given by Solr?
  • Calling a second level base class constructor
  • What is the first step to using a REST API in Rails?
  • Proguard Exception java.io.IOException: Duplicate zip entry
  • Loopback validation on Properties who's types are other Models
  • python: forcing relative imports to search from script file
  • EntLib Way to Bind “Null” Value to Parameter
  • multidatatrigger with multibinding in ControlTemplate.Triggers
  • “mvn clean generate-source” could not resolve dependencies
  • Xamarin MonoAndroid Azure mobile service InsertAsync
  • Cloud Code function running twice
  • How to programatically 'login' a user based on 'remember me' cookie when using j
  • Fail:(TESTMODE) Transactions of this market type cannot be processed on this system
  • SetWindowsHookEx does not react on media keys
  • Web.config system.webserver errors
  • Unable to install Git-core+svn by MacPorts
  • Django simple Captcha “No module named fields” error
  • Thread safety of a fluent like class using clone() and non final fields
  • Converting a WriteableBitmap image ToArray in UWP
  • Custom Tabgroup Appcelerator
  • iOS: Detect app start via notification press
  • Could not find rake using whenever rails
  • Initializer list vs. initialization method
  • How to add a column to a Pandas dataframe made of arrays of the n-preceding values of another column
  • How to make Safari send if-modified-since header?
  • Function pointer “assignment from incompatible pointer type” only when using vararg ellipsis
  • 0x202A in filename: Why?
  • How to pass list parameters for each object using Spring MVC?
  • Why joiner is not used after Sequence generator or Update statergy
  • Setting background image for body element in xhtml (for different monitors and resolutions)
  • Can Visual Studio XAML designer handle font family names with spaces as a resource?
  • File not found error Google Drive API
  • JaxB to read class hierarchy
  • Android Heatmap on canvas or ImageView