Nikolay
Nikolay

Reputation: 1121

Force Maven use only first level dependencies

I have a Maven Java project. I don't want my project dependencies to be satisfied by chance through a chain of subdependencies when compiling the project. It is OK for me when building the final war when maven must check all used dependencies and add necessary libs to the war, but when compiling the code I want to be sure that only direct dependencies are used. Why?

Let's say I have two dependencies:

<dependency>
    <groupId>com.package</groupId>
    <artifactId>module-1</artifactId>
</dependency>

<dependency>
    <groupId>com.package</groupId>
    <artifactId>module-2</artifactId>
</dependency>

For our project module-1 and module-2 serve completely different purposes, but somewhere in the dependency tree of module-2, module-1 is used. I delete module-1 dependency, but maven continue to build my project without compilation errors, because it resolves module-1 from module-2 sub-dependencies. This change goes unnoticed.

After sometime we decide to remove module-2, because we don't need it. Strange enough but we can not any more compile classes which were using imports from module-1 and which are not connected to module-2 logic.

This is a simple case, but in big project this can make quite a dependency mess.

Upvotes: 5

Views: 7385

Answers (4)

Ben Thurley
Ben Thurley

Reputation: 7141

If you really need to do this then you can setup exclusions in the pom.

e.g. here's an example of an exclusion in one of my poms where I don't want it to automatically get commons-logging because I'm using a different logging provider.

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${org.springframework-version}</version>
        <exclusions>
            <!-- Exclude Commons Logging in favor of SLF4j -->
            <exclusion>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
             </exclusion>
        </exclusions>
    </dependency>

You could do something like this (untested)

<dependency>
    <groupId>com.package</groupId>
    <artifactId>module-2</artifactId>
    <exclusions>
      <exclusion>
        <groupId>com.package</groupId>
        <artifactId>module-1</artifactId>
      </exclusion>
    </exclusions>
</dependency>

I wouldn't necessarily recommend this though. It makes sense in the case of my logging exclusion because I'm using slf4j instead of commons logging. I've seen other examples where this is used to exclude spring 2 if the project as a whole is using spring 3.

It's a bit difficult to tell from your example because it's so vague. In general you should keep your dependencies to a minimum. If module-2 depends on module-1 then it implies that your application won't compile or run without module-1. If in fact it can live happily without it then it's not really dependent.

As a side note it's a bit alarming that you don't have a version number against the dependencies. You'll probably find maven warns you about this. It's good practice to always include a version number. If you're dependent on a module which is currently in development then you should use the .SNAPSHOT suffix on the version to get the latest build for that version.

Upvotes: 2

Andrey Chaschev
Andrey Chaschev

Reputation: 16476

There seems to be no way to tell maven not to resolve dependency transitively: How to exclude all transitive dependencies of a Maven dependency. One of the reason's I think, is that the user can soon run into runtime troubles, when he finds that some of the artifacts are not being resolved at runtime or there are artifact versions problems. However, if you check the link out, you can make each of the deps 'standalone' with a wildcard exclusion pattern.

One other option is to use <optional> dependency for each of your module-X sub-dependencies. This will make sure the project compiles and non of your module-X would be resolved transitively. Like:

<dependency>
   <groupId>com.package</groupId>
   <artifactId>module-1</artifactId>
   <optional>true</optional>
</dependency>

Still, analyzing the dependency tree might be the most safe and predictable choice.

Upvotes: 1

rec
rec

Reputation: 10895

You can use the Maven dependency plugin goal "dependency:analyze" to give you a report of all used dependencies which are not declared on the current module (included transitively). That way Maven will still use transitive dependencies (no way around that I guess), but you can force yourself via the plugin to make sure these are also declared. It will also warn you of unnecessary dependencies. Mind, the plugin analyzes the compiled classes. At times, you may need to configure the plugin, because occasionally it may not detect that a dependency is required at compile time but not at runtime, e.g. because a constant was inlined.

Upvotes: 6

wemu
wemu

Reputation: 8160

It does sound a bit strange what you plan to do. In a way you sabotage the dependency management you want to use.

If your module-2 depends on module-1 and has a dependency to it, then any module that depends on module-2 only need to define that one.

You may be able to restrict the depth of the resolution using exclusions: Exclude all transitive dependencies of a single dependency

Newer versions of maven allow wildcards in those.

But: you will need to re-add the ones you actually need, this is by repeating the dependencies you have an other modules. This duplicates the work.

If there are artifacts that cause weirdness it may be possible to define a scope: http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html so it is not propagated to dependant modules as well.

Upvotes: 0

Related Questions