5 Replies Latest reply on Jan 13, 2012 6:58 AM by Ben Kirby

    How to make WAR in EAR see EAR module classes?

    Ben Kirby Newbie

      Hi, I've got an EAR archive which contains a JAR module and a WAR module.

       

      When deployed on (a fairly old version of) jboss-as-7.1.0.Alpha1-SNAPSHOT, everything deploys fine. However, when classes from within the WAR file are running, they can't see the classes in the JAR file:

       

      org.jboss.weld.exceptions.UnsatisfiedResolutionException: WELD-001308 Unable to resolve any beans for Types: [class core.service.Service]; 
      Bindings: [@javax.enterprise.inject.Any(), @core.job.JobBinding(value=SERVICE_A)]
      

       

      The correctly annotated classes managed beans are definitely in the JAR module, the WAR classes just can't see them.

       

      ear-subdeployments-isolated is left as default (false), so libs from JAR should be visible to WAR.

       

      I'm intrigued by the note at https://docs.jboss.org/author/display/AS7/Class+Loading+in+AS7:

       

      Using the export parameter it is possible to add a dependency to all sub deployments in an ear. If a module is exported from a Dependencies: entry in the top level of the ear (or by a jar in the ear/lib directory) it will be available to all sub deployments as well

       

      I've tried adding

       

      deployment.my_ear.ear.my_jar.jar export
      

       

      to the manifest of either the EAR or the WAR, and get this exception:

       

       

      Caused by: org.jboss.modules.ModuleLoadException: Circular export path in deployment.my_ear.ear:main
              at org.jboss.modules.Module.linkExports(Module.java:850)
              at org.jboss.modules.Module.linkExports(Module.java:844)
              at org.jboss.modules.Module.linkExportsIfNeeded(Module.java:1146)
              at org.jboss.modules.ModuleLoader.loadModule(ModuleLoader.java:180)
              at org.jboss.modules.Module.linkExports(Module.java:921)
              at org.jboss.modules.Module.linkExports(Module.java:844)
              at org.jboss.modules.Module.linkExportsIfNeeded(Module.java:1146)
              at org.jboss.modules.ModuleLoader.loadModule(ModuleLoader.java:180)
              at org.jboss.modules.Module.linkExports(Module.java:921)
              at org.jboss.modules.Module.linkExports(Module.java:844)
              at org.jboss.modules.Module.linkExportsIfNeeded(Module.java:1146)
              at org.jboss.modules.ModuleLoader.loadModule(ModuleLoader.java:180)
              at org.jboss.modules.ModuleLoader.loadModule(ModuleLoader.java:172)
              at org.jboss.as.server.moduleservice.ModuleLoadService.start(ModuleLoadService.java:63)
      
      

       

      So I must be doing something wrong. Is this the correct way to make the WAR see the JAR module's classes, and, if so, what's the necessary syntax and placement? Archives are all built with Maven, so it'd have to go in one of the poms.

       

      Hope you can help, thanks.

        • 1. Re: How to make WAR in EAR see EAR module classes?
          Stephen Coy Master

          By default, WAR modules can only "see" classes in an EAR's EJB modules and the EAR/lib module. Everything in the EAR/lib directory is considered to be a single module.

           

          If you have a regular JAR (no EJBs) sitting in the root of the EAR, then the WAR will not be able to see it's classes unless it has an explicit manifest classpath entry for it. The simplest solution is to put these jar files in the EAR/lib directory instead.

           

          Other posters also had similar issues when their WAR modules were "exploded" inside the EAR.

          • 2. Re: How to make WAR in EAR see EAR module classes?
            Ben Kirby Newbie

            Thanks for the quick reply, Stephen. I've given that a go, but am now getting a different error. I'll explain the EAR/pom structure a bit better, maybe I'm still doing someting wrong.

             

            EAR pom:

             

            ...
            <dependencies>
                      <dependency>
                                <groupId>${project.groupId}</groupId>
                                <artifactId>my_jar</artifactId>
                                <version>${project.version}</version>
                                <scope>provided</scope>
                      </dependency>
                      <dependency>
                                <groupId>${project.groupId}</groupId>
                                <artifactId>my_war</artifactId>
                                <version>${project.version}</version>
                                <type>war</type>
                                <scope>provided</scope>
                      </dependency>
            ...
            <build>
                      <plugins>
                                <plugin>
                                          <groupId>org.apache.maven.plugins</groupId>
                                          <artifactId>maven-ear-plugin</artifactId>
                                          <configuration>
                                                    <displayName>my_ear</displayName>
                                                    <modules>
                                                              <jarModule>
                                                                        <groupId>${project.groupId}</groupId>
                                                                        <artifactId>my_jar</artifactId>
                                                                        <includeInApplicationXml>false</includeInApplicationXml>
                                                                        <bundleDir>/lib</bundleDir> <!-- this is what I've just added -->
                                                              </jarModule>
                                                              <webModule>
                                                                        <groupId>${project.groupId}</groupId>
                                                                        <artifactId>my_war</artifactId>
                                                              </webModule>
                                                              <jarModule>
                                                                        <groupId>org.jboss.seam.persistence</groupId>
                                                                        <artifactId>seam-persistence</artifactId>
                                                                        <includeInApplicationXml>false</includeInApplicationXml>
                                                                        <bundleDir>/lib</bundleDir>
                                                              </jarModule>
                                                              <jarModule>
                                                                        <groupId>org.jboss.seam.solder</groupId>
                                                                        <artifactId>seam-solder</artifactId>
                                                                        <includeInApplicationXml>false</includeInApplicationXml>
                                                                        <bundleDir>/lib</bundleDir>
                                                              </jarModule>
              
                                                              [...more modules I need in the lib directory...]
            

             

            This generates an EAR with the JAR module in libs, and the WAR at the root level - before I specified a bundleDir, the JAR module was on the root level.

             

            However, nothing in the new EAR is able to deploy; I immediately get

             

            09:44:59,902 INFO  [controller] (DeploymentScanner-threads - 1) () Deployment of "my_ear.ear" was rolled back with failure message {"Services with missing/unavailable dependencies" => ["jboss.deployment.unit.\"my_ear.ear\".PARSE missing [ jboss.deployment.subunit.\"my_ear.ear\".\"lib/my_jar.jar\".STRUCTURE ]"]}
            09:44:59,925 INFO  [deployment] (MSC service thread 1-20) () Stopped deployment lib/my_jar.jar in 22ms
            09:45:00,020 INFO  [deployment] (MSC service thread 1-1) () Stopped deployment my_war.war in 115ms
            09:45:00,101 INFO  [deployment] (MSC service thread 1-3) () Stopped deployment my_ear.ear in 199ms
            09:45:00,102 ERROR [deployment] (DeploymentScanner-threads - 2) () {"Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-2" => {"Services with missing/unavailable dependencies" => ["jboss.deployment.
            unit.\"my_ear.ear\".PARSE missing [ jboss.deployment.subunit.\"my_ear.ear\".\"lib/my_jar.jar\".STRUCTURE ]"]}}}
            

             

            Is this not the correct way to put the module in the lib dir?

             

            As an aside, the class that can't be seen in the JAR is actually an EJB singleton. Before I added the WAR to the EAR, the JAR would deploy fine, including the singleton. Could another approach be to put the EJB singleton class in a separate EJB module (referenced as such in the build section of the EAR plugin)? I'd rather not do that unless absolutely necessary, however...

            • 3. Re: How to make WAR in EAR see EAR module classes?
              Stephen Coy Master

              Ben Kirby wrote:

              ...

               

              Is this not the correct way to put the module in the lib dir?

               

              ...

              Nup!

               

              All of those <jarModule> elements are redundant.

               

              Specify all of your direct dependencies at runtime or compile scope.

               

              The jar that contains the EJB singleton should be specified as an <ejbModule>. The maven module that builds it should specify

               

                  <packaging>ejb</packaging>

               

              Don't forget to specify it's type as "ejb" in the dependencies section of the EAR's pom.

               

              And finally, specify

               

                  <defaultLibBundleDir>lib</defaultLibBundleDir>

               

              in the maven-ear-plugin configuration.

               

              A huge side effect of changing the dependency scope from provided to runtime/compile is that you will suck in all the transient dependencies. You may have to add explicit exclusion elements to some of those deps, especially for your WAR modules.

              • 5. Re: How to make WAR in EAR see EAR module classes?
                Ben Kirby Newbie

                Brilliant - thanks a lot Stephen.

                 

                We've made the fixes to our poms, and having the JAR as an ejbModule allows it to be seen by the WAR, as you said.

                 

                Turns out the WAR didn't need any of its own libs, they were all in EAR/lib, so just excluded them all in one go with packagingExcludes like:

                 

                <build>
                    <plugins>
                      <plugin>
                        <artifactId>maven-war-plugin</artifactId>
                        <version>2.1.1</version>
                        <configuration>
                          <packagingExcludes>WEB-INF/lib/*.jar</packagingExcludes>
                          <archive>
                            <manifest>
                              <addClasspath>true</addClasspath>
                              <classpathPrefix>lib/</classpathPrefix>
                            </manifest>
                          </archive>
                        </configuration>
                      </plugin>
                    </plugins>
                  </build>
                
                

                 

                as at http://maven.apache.org/plugins/maven-war-plugin/examples/skinny-wars.html.

                 

                All deploys and works now! Thanks again.