Should I rely on transitive dependencies in Maven if they come from other sub-module of my parent?
Asked Answered
T

3

11

Suppose we are working on mortgage sub-module, and we are directly using the Google Guava classes in module code, but the dependcy for the guava is defined in other sub-module under the same parent and we have access to Guava classes only by transitive dependency on "investment" module:

banking-system (parent pom.xml)
|
|-- investment (pom.xml defines <dependency>guava</dependency>)
|
|-- mortgage (pom.xml defiens <dependency>investment</dependency>)

Should we still put a <dependency> to Guava in the mortgage pom.xml?

The cons looks like duplication in our pom.xml, the pros are: if someone developing "investment" will drop guava, then it will not stop our mortgage sub-module from being successfuly build.

If yes, then what <version> shoudle we specify? (none + <dependencyManagement> in parent pom?)

If yes, should we use a <provided> scope in some module then?

Note: Keep in mind, that I am asking in specific situation, when modules have common parent pom (e.g. being an application as whole).

Maybe this structure was not the best example, imagine:

banking-app
    banking-core (dep.on: guava, commons, spring)
    investment (dep.on: banking-core)
    mortgage (dep.on: banking-core)

Should still Investment explicitly declare Spring when it use @Component, and declare Guava if it uses Guava's LoadedCache?

Tramel answered 13/11, 2017 at 9:27 Comment(2)
I would duplicate and let dependencyManagement in the parent take care of the version.Unveiling
Possible duplicate of Maven : Should I keep or remove declared dependencies that are also transitives dependencies?Sellers
E
17

we are directly using the Google Guava classes in module code, but the dependcy for the guava is defined in other sub-module under the same parent and we have access to Guava classes only by transitive dependency on "investment" module [...] Should we still put a to Guava in the mortgage pom.xml?

Yes, you should declare Google Guava dependency in your module and not expect it to be available as transitive-dependency. Even if it works with the current version, it may not be the case anymore in later versions of direct dependencies.

If your code depends on a module, your code should depends only directly on classes of this module, not a transitive-dependency of this module. As you mentioned, there is no guarantee that the investment module will continue to depend on Guava in the future. You need to specify this dependency either in the parent's pom.xml or in the module itself to ensure it will be available without relying on transitive dependencies. It's not duplication as such, how else can you tell Maven your module depends on Guava?

I do not see any situation in which minimal best practices are respected where you would need to do otherwise.

If yes, then what <version> shoudle we specify? (none + <dependencyManagement> in parent pom?)

Yes, using <dependencyManagement> in parent and using a <dependency> in your child module without version is best: you will make sure all your modules uses the same version of your dependency. As your modules are an application as a whole, it is probably better as it will avoid various issues such as having different versions of the same dependency being present on the classpath causing havoc.

Even if for some reason one of your module using the same parent requires a different version of our dependency, it will still be possible to override the version for this specific module using <version>.

If yes, should we use a scope in some module then?

Probably not, having the dependency with a compile scope is the best wat to go with most packaging methods.

However you may have situations where you need or prefer to do this, for example if said modules requires to use a runtime environment specific version, or if your deployment or packaging model is designed in a way that demands it. Given the situation you expose, both are possible, though most of the time it should not be necessary.

Elbertina answered 16/11, 2017 at 16:15 Comment(0)
H
3
  1. Yes, declare the dep. It's not a duplication!!! That compile dependencies are transitive is not intended by the maven developer, it's forced by the java-language. Because features like class-inheritance forces this behavior. Your already mentioned "pro" is the important fact. See the (*) note in the transitive-scope-table

  2. Yes, always declare needed third party lib-versions in your reactor parent with dependencyManagement. It's a pain to find errors from different lib-versions at runtime. Avoid declaring versions of third-party libs in sub-modules of large reactors, always use a depMngs in parent.

  3. No, i would use "provided" only for dependencies provided from the runtime, in your example tomcat/jboss/wildfly/.. for things like servlet-api/cdi-api/. But not for third party libraries. Declare the "provided" scope as late as possible (i.e. your deployment(s) module war/ear) not in your business modules. This makes it easier to write tests. For example:

    • investment (depends on guava scope:=provided)
    • mortgage (depends on investment, but don't need guava himself)

--> mortgage classpath doesn't contain guava. If you write a unit-test for mortgage where classes involved from investment it will not work -> you need to declare at least guava with scope=test/runtime to run these tests...

Henrieta answered 15/11, 2017 at 19:47 Comment(0)
T
0

When a module uses a 3rd party library, the module should explicitly depend on that library in its pom.xml too. Imagine if another project should use the 'mortgage' module, and doesn't depend on Guava already, it will fail e.g. when a unit test comes upon a code path that involves Guava. An explicit dependency also covers you against the scenario where you refactor the 'investment' module so that it doesn't use Guava anymore. Your 'investment' module should be agnostic to such changes in its dependencies.

It's always correct to explicitly list your direct dependencies. When it comes to version, it's best to keep that in the dependencyManagement section of your parent pom so all child projects inherit that (same) version.

Tut answered 13/11, 2017 at 12:35 Comment(2)
But remember that mortgage module explicitly require investment module, so when someone will depend on mortgage "ony", it will anyway pull the investment with guava alsoEustacia
Explicit dependencies is still the way to go for all code that is used in your module. I updated my answer with another example.Tut

© 2022 - 2024 — McMap. All rights reserved.