Maven WAR Plugin
  1. Maven WAR Plugin
  2. MWAR-21

Need a way to include limited set of webapp's dependencies

    Details

    • Type: Improvement Improvement
    • Status: Closed Closed
    • Priority: Blocker 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.

      1. AbstractWarMojo.diff
        3 kB
        Dirk Olmes
      2. AbstractWarMojo.patch
        11 kB
        Jason Melnick
      3. MWAR-21-workaround.patch
        4 kB
        Mark Chesney

        Issue Links

          Activity

          Hide
          Mark Chesney added a comment -

          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.

          Show
          Mark Chesney added a comment - 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.
          Hide
          Mark Chesney added a comment -

          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.

          Show
          Mark Chesney added a comment - 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.
          Hide
          Al Robertson added a comment -

          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?

          Show
          Al Robertson added a comment - 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?
          Hide
          Jason Melnick added a comment -

          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.

          Show
          Jason Melnick added a comment - 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.
          Hide
          Jason Melnick added a comment -

          Fixes optional dependency transitive inclusion and root-level depth > 1 dependencies

          Show
          Jason Melnick added a comment - Fixes optional dependency transitive inclusion and root-level depth > 1 dependencies

            People

            • Assignee:
              John Tolentino
              Reporter:
              Dirk Olmes
            • Votes:
              1 Vote for this issue
              Watchers:
              10 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Time Tracking

                Estimated:
                Original Estimate - Not Specified
                Not Specified
                Remaining:
                Remaining Estimate - 0 minutes
                0m
                Logged:
                Time Spent - 6 hours
                6h