Details
-
Type:
Improvement
-
Status:
Closed
-
Priority:
Blocker
-
Resolution: Fixed
-
Affects Version/s: None
-
Fix Version/s: 2.0
-
Component/s: None
-
Labels:None
-
Environment:M2.0.1
-
Number of attachments :3
Description
I need a way to pack a war that includes only a limited set of the webapp's dependencies. We're deploying in mainly two different environments: for testing, the webapp runs standalone and thus needs to include all its dependencies in the war. For production we deploy the webapp into a JBoss server that has all the dependencies already installed.
I've modified AbstractWarMojo in the following way: 1) allow to specify dependencyIncludes an dependencyExcludes (as lists) 2) upon building the war, each dependency is checked against the excludes and the includes and will be added to the war accordingly.
While this patch may not be the best way to to it, it clearly shows my requirements.
-
- AbstractWarMojo.diff
- 27/Dec/05 1:43 AM
- 3 kB
- Dirk Olmes
-
- AbstractWarMojo.patch
- 25/Jun/07 12:36 PM
- 11 kB
- Jason Melnick
-
- MWAR-21-workaround.patch
- 26/Mar/06 6:43 AM
- 4 kB
- Mark Chesney
Issue Links
Activity
Ok, I wasn't clear enough ...
The structure looks more like the following:
webapp
struts
our-ejb-facade
ejb1-client
ejb2-client
ejb3-client
...
The problem is not the dependencies of the webapp itself, it's all the transitive dependencies of the our-ejb-facade module that I need to package or skip.
I've played around with <scope>provided</scope> on the dependencies for our-ejb-facade but this is not what I want: to run from the development machines, I need ejb-client*, only for deployment on the production server, those dependencies have to be omitted. So for me it's really a packaging thing more than a dependency management thing.
And no, I don't want to duplicate all the dependencies of our-ejb-facade in the webapp's pom.
I'm packaging three .war files in a .ear. They share most of their dependencies.
I'm therefore going to include the dependencies as .jar files in the .ear and have them loaded in my container by the EJB ClassLoader. I don't want the .jar files packed into both of the .war files.
All I need is a switch to say "don't include any of the .jar dependencies".
One option might be simply to remove the dependencies from my .war pom.xml files. This is not desirable. Why? Because, I want Maven to work out which dependencies to pack in the .ear file.
It looks like there is a missing dependency scope. The one that is required for compilation but not in the runtime.
>It looks like there is a missing dependency scope. The one that is required for compilation but not in the runtime.
I strongly agree with this comment. However, I fundamentaly don't understand why "provided" scope doesn't declare transitive dependencies (which would make it exactly fit the bill of a scope that was required for compilation but not for runtime)
Reasoning:
If a subproject is dependent at runtime on a particular product then surely the superproject will, at the end of the day, need that product on its runtime classpath. This is the normal use-case. On the odd occasion that we don't want this behaviour, the developer can "exclude" unwanted dependencies and then have a talk with the person who manages the subproject and say "do you really need this dependency at runtime?".
Speaking of use cases, it worries me that Maven doesn't have a simple description of expected use cases for each plugin right at the top of the documentation. An example that relates to this Jira issue is:
Use Case: Developer packages multiple war files in an ear and wants to consolidate the dependencies onto the ear classpath. This involves:
1. Excluding the dependency jar files from the war files.
2. Marking the war files in a way that the ear file generation process will know to include them.
3. Changing the ear plugin behaviour so that when it sees that jars are excluded from the war they are ear.
4. Create entries in the war manifest so that the dependent jars can be loaded from the ear classloader.
Not an easy use case, by any means, but a very, very common one and one that Maven 2 does not currently support.
Brett, I can't say about subset, but there is no way to exclude certain dependencies from being packaged into war. Eg. servlet-api-2.4.jar is required for most of the sevlet or web framework but it should not be packaged into war because api is provided by container.
In case when war is packaged within EAR it is even worse, because it may be necessary to put dependencies into EAR in order to be loaded by common classloader between war, ejb jar and rar. So, such common classes must NOT be packaged in war.
BTW, I am not sure if proposed patch is the best idea. m1 allowed to mark artifacts that need to be packaged, but with m2 it looks like there stould be special scope or some additional metadata in for dependencies.
I think it's partly my fault. I took the assignement of this issue too early and I am NOT actually working on it.
Eugene, provided scope is for dependencies like servlet-api, jsp-api, etc. (that are needed for compile, but will be present in the container)
Grzegorz , thats great. But dependencies with such scope currently still included into war.
I made a test and they were included in the war. A deleted my local repository war plugin and
a) made a test, 2.0-beta-2 version was used - everything ok
b) built trunk version (2.0-beta-3-SNAPSHOT) - everything ok too.
I don't know what version I had in my repository. I know only that is was a snapshot.
Try to delete maven-war-plugin from your local repo and try again.
DIRK OLMES:
Usecase: Pack a war that includes only a limited set of the webapp's dependencies.
Solution: Profiles
Usecase: To run from the development machines, need ejb*-client, only. And for deployment on the production server, those dependencies have to be omitted.
Solution: Still profiles. Create a "test" profile where the dependencies used only for the development machines (ejb*-client) are declared.
Concern: Don't want to duplicate all the dependencies of our-ejb-facade in the webapp's pom.
Answer: There will be no duplicates here because, like what Trygve said, you only need to declare the uncommon artifacts (in this case your ejb*-client dependencies).
Related URL:
--------------------------------
DAVID BODEN:
Usecase: Packaging three .war files in a .ear. They share most of their dependencies. Same as "Developer packages multiple war files in an ear and wants to consolidate the dependencies onto the ear classpath."
EAR-PROJECT (parent)
- WAR1 (child-module)
- WAR2 (child-module)
- WAR3 (child-module)
Need to include the dependencies as .jar files in the .ear and have them loaded in my container by the EJB ClassLoader.
But don't want the .jar files packed into both of the .war files.
Solution:
PARENT-POM
- EAR-PROJECT
- PARENT-POM2
- WAR1
- WAR2
- WAR3
Declare common dependencies in WAR1, WAR2 and WAR3 in PARENT-POM2 with provided scope.
Also declare these dependencies (without the provided scope) in the EAR project.
Add WAR1, WAR2 and WAR3 to EAR-PROJECT's dependencies as well.
Verified this setup works in a similar project. WAR1, WAR2 and WAR3 builds but their common dependencies are not included in the wars. EAR-PROJECT includes all the WARs and their dependencies in its packaging.
--------------------------------
EUGENE KULESHOV:
Need: Dependency scope that is required for compilation but not in the runtime. Same As "Way to exclude certain dependencies from being packaged into war. Eg. servlet-api-2.4.jar is required for most of the sevlet or web framework but it should not be packaged into war because api is provided by container."
Answer: Provided scope, As was mentioned by Grzegorz Slowikowski. Also verified this and war builds but does not add jars with provided scope.
Related URLs:
You're missing an important aspect of J2EE packaging. If a dependency is included in the EAR to be used by J2EE modules within the same EAR, it must be listed in the manifest of that module. To have these dependencies included in the manfiest of the WAR using existing mechanisms, the WAR plugin must be configured like like so:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
Provided scope dependencies will not be included in the WAR manifest. Compile and Runtime scope dependencies will be added to the WAR manifest. The WAR plugin also packages compile and runtime scope libraries in WEB-INF/lib. Not only is this redundant, but it can cause Class Cast Exceptions. The J2EE spec allows for any combination of WAR dependencies packaged in the EAR or within WEB-INF/lib, not just one or the other. Please see the J2EE 1.4 specification (http://java.sun.com/j2ee/j2ee-1_4-fr-spec.pdf) section 8.2, for valid J2EE packaging use cases.
I am attaching the workaround I use which supports the use case where all webapp dependencies are in the EAR. The workaround is activated when the the archive.manifest.addClasspath configuration property is set to true like so:
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
Not bundling runtime/compile dependencies for a WAR packaged within an EAR is necessary because of the J2EE spec application assembly requirement 8.3.1e: There must be only one version of each class in an application.
This workaround does not support the use case of a combination of EAR and WEB-INF/lib dependencies which the J2EE spec supports.
I am surprised this is marked as fixed. I don't believe it is.
Here is a structure that J2EE requires you to support
ear
jar1
war ->manifest classpath:jar1
jar2
war depends on jar1 and jar2
Currently, you can specify to add a manifest classpath entry. This adds an entry for each dependency that is not "Provided", because provided means "provided by the container". (CORRECT)
In the above example, I can't configure maven to exclude jar1 from the war/WEB-INF/lib dir but include it in the classpath manifest.
It appears to me that we need another dependency attribute to accompany scope "Provided", say <providedByManifestClasspath>true</providedByManifestClasspath> or a <providedBy>CONTAINER|MF-CP</providedBy> etc.
In this solution, we wouldn't need the manifest->addClasspath plugin config. The war builder would only include the artifact in the war when the scope wasn't provided and the war archiver would know when to include the dependency in the manifest classpath.
You would still require the manifest classpath prefix config.
Does this make sense?
Is there a way to accomplish this already?
No, this isn't fixed.
Although the war plug-in's documentation has examples of how to do this it doesn't work properly due to a problem with M2's resolution of optional dependencies: see http://jira.codehaus.org/browse/MNG-3067
I have a fix for it (the war plugin, not the dependency mechanism) of which I'll post the patch ASAP...
The problem is that somehow optional dependencies are being resolved for optional dependencies arbitrarily.
The fix involves removing ResolutionNodes at the parent-level w/ a depth > 1 from the ArtifactResolutionResult as well as removing artifacts that are optional.
Fixes optional dependency transitive inclusion and root-level depth > 1 dependencies
I think you can solve this more elegantly by having a "test" profile with the extra set of dependencies.