Search code examples
javamavenmaven-3pom.xmlmaven-dependency

How can I use dependencies of a project that's been marked as provided?


I have the following scenario, simplified:

projectX  ---> projectA ---> projectB

Where ---> means "depends on".

ProjectB is really simple. It doesn't declare any dependenci. In fact, the only relevant part is this:

<packaging>jar</packaging>

In pom.xml of projectA I have declared the dependency to projectB:

<packaging>jar</packaging>
<dependencies>
    <dependency>
        <groupId>com.mycompany</groupId>
        <artifactId>projectB</artifactId>
        <version>1.0.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

And in pom.xml of projectX I have:

<packaging>war</packaging>
<dependencies>
    <dependency>
        <groupId>com.mycompany</groupId>
        <artifactId>projectA</artifactId>
        <version>1.0.0</version>
        <scope>compile</scope>
    </dependency>
</dependencies>

The problem is that projectX needs to use components (classes and such) that are defined in projectB. If I change the scope in projectA to use compile for projectB, everything will work, but then projectB will be included when generating the war in projectX, and I need to have this library out of the generated war because I'm providing projectB in other part of the project.

In the real scenario, I have several dependencies like projectB that affect projectA, so to reduce the size of the generated war, I would like to set them as provided, but then projectX cannot use the components defined in any of those libraries. Example of components: Spring, Hibernate, etc.

Question: Is there a way to achieve this in a clean way without re-declaring dependencies in lots of places?


Solution

  • The problem is that projectX needs to use components (classes and such) that are defined in projectB.

    Then ProjetB should be a dependency of ProjectX indeed, in provided scope, again. Re-declaring the dependency would change how Maven would handle it as transitive dependency (that is, you can override its behavior by saying: I want this dependency in my project with this scope).

    but then projectB will be included when generating the war in projectX, and I need to have this library out of the generated war

    This will not happen by re-declaring it in provided scope. Alternatively, you could change the scope of ProjectB in ProjectA to compile and then configure the maven-war-plugin to exclude them, using inclusions/exclusions.
    Before doing so though, you should double-check why semantically (or requirements-wise) ProjectB was set as provided in ProjectA and what would be its impact on other consumer projects.


    Update
    Both approaches above may suit your needs. Alternatively, as suggested in comments further options could be more sustainable and clear in the long run towards a better governance and maintenance (centralization):

    • Use a common parent pom where you could declare the list of shared dependencies, that is, dependencies that will be used by all children projects, defined (and maintained) once.
    • Use the dependencyManagement section in ProjectX to change how Maven dependencies mediation would handle transitive dependencies on ProjectA, without changing ProjectA or ProjectB (similar to option 1 at the top of this answer, with the difference that it will only be applied whenever the dependency comes into scope and ignored otherwise). To centralize this management, again, would be better to do so in a common parent (option above).