maven-war-plugin
maven-war-plugin copied to clipboard
[MWAR-351] Optional dependency not being included in the WEB-INF/lib folder
Hockchai Lim opened MWAR-351 and commented
I've a maven web module that has several dependencies that are declared with <optional>true</optional> in pom.xml. For example: <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <optional>true</optional> </dependency>
When performing packaging of this project, Maven WAR Plugin is not including those optional dependencies to the WEB-INF/lib folder, which I think is incorrect. According to https://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html, optional dependency should work like transitive dependency for this web module. Optional dependency should only be ignored on projects/modules that reference this web modle.
Below is the relevant sections from https://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html link:
How do optional dependencies work? Project-A -> Project-B The diagram above says that Project-A depends on Project-B. When A declares B as an optional dependency in its POM, this relationship remains unchanged. Its just like a normal build where Project-B will be added in its classpath.
Project-X -> Project-A But when another project(Project-X) declares Project-A as a dependency in its POM, the optional dependency takes effect. You'll notice that Project-B is not included in the classpath of Project-X; you will need to declare it directly in your POM in order for B to be included in X's classpath.
Affects: 2.2
1 votes, 5 watchers
Michael Osipov commented
Probably the documentation is not clear on this. Why do you want to use optional deps with WAR files at all?
Hockchai Lim commented
This WAR module is really a EJB module. I followed Tomee's suggestion on packaging a EJB in WAR file (http://tomee.apache.org/deploying-in-tomee.html). So, this WAR module is really a EJB server app. All the dependencies declared in this module are for this module only. For all its ejb client modules, I would do below to include the ejb client jar: <dependency> <groupId>MyEJBGroupID</groupId> <artifactId>MyEJBArtifactId</artifactId> <version>1.0</version> <type>ejb-client</type> </dependency>
ejb client module does not need server's transitive dependencies, and hence the optional attribute are added to them.
The purpose of optional dependency is to allow the author to declare dependency for a project/module that is strictly for that project/module only. The WAR plugin not including optional dependency in WEB-INF/lib for that project/module seems to be breaking the purpose of this attribute.
Vsevolod Golovanov commented
In contrast, we're using optional in WAR as a way to build different WARs for different customers.
<dependency>
<groupId>my.company</groupId>
<artifactId>ui-module-a</artifactId>
<optional>${module-a-excluded}</optional>
</dependency>
<dependency>
<groupId>my.company</groupId>
<artifactId>ui-module-b</artifactId>
<optional>${module-b-excluded}</optional>
</dependency>
...
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<classifier>${customer-classifier}</classifier>
</configuration>
</plugin>
The parent pom has profiles defining customers and their modules.
This mirrors ear filtering:
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<configuration>
<classifier>${customer-classifier}</classifier>
<modules>
<ejbModule>
<groupId>my.company</groupId>
<artifactId>ejb-module-a</artifactId>
<excluded>${module-a-excluded}</excluded>
</ejbModule>
<ejbModule>
<groupId>my.company</groupId>
<artifactId>ejb-module-b</artifactId>
<excluded>${module-b-excluded}</excluded>
</ejbModule>
</modules>
</configuration>
</plugin>
I'm unaware of another way to achieve this given this set of properties.
elharo commented
This might be working as intended. "When A declares B as an optional dependency in its POM, this relationship remains unchanged. Its just like a normal build where Project-B will be added in its classpath....But when another project(Project-X) declares Project-A as a dependency in its POM, the optional dependency takes effect. You'll notice that Project-B is not included in the classpath of Project-X; you will need to declare it directly in your POM in order for B to be included in X's classpath." That is, it's all about the classpaths.
So what's the classpath and what's the app in this scenario? In particular, is there a classpath for the web module that is unique to the web module? Or is there a separate, larger process that includes the files from the web module but also includes other things in the classpath?
Another way of thinking about it: is there an app that depends on the web module that is running? (in which case the optional dependency should not be inlcuded) or is the web module the app? (in which case it should be included).
Now if multiple class loaders are being used then it gets still more complex. I'm personally not sure what the right answer is here.