jakarta-eemavenclasspathearmaven-ear-plugin

In java EE, which jars should I put in the library dir?


I have a Java EE project. The project is built using maven into an .ear archive. There is a library jar containing a JPA 2 persistence unit, which is located in the library directory of the ear (so multiple other modules can use it).

While adding an implementation of Shiro's Permission interface as an entity in this persistence unit, I had trouble getting the ear to deploy correctly, because the shiro classes where unavailable in the persistence unit. I eventually figured out that I needed to put all dependencies (applied also to transitive deps) of the library jar in the library directory to get it to deploy.

So the final layout look roughly like this:

ear
`- lib
   `- persistence-unit.jar
    - shiro-core.jar
    - slf4j-api.jar
 - module1
 - moduleN
 - library1.jar
 - libraryN.jar

Now, for the questions:

  1. Are there any guide lines for what should be put in the library directory, and is my solution generally acceptable?
  2. Why aren't the libraries in the root of the ear available to the jars in the lib directory?
  3. Why doesn't maven figure this out automatically?

EDIT: pom.xml for the ear

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <artifactId>ear</artifactId>
    <packaging>ear</packaging>

    <parent>
        <groupId>com.example</groupId>
        <artifactId>project</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-ear-plugin</artifactId>
                <version>2.7</version>
                <configuration>
                    <modules>
                        <webModule>
                            <!-- ... -->
                        </webModule>
                        <ejbModule>
                            <!-- ... -->
                        </ejbModule>
                        <jarModule>
                            <groupId>com.example</groupId>
                            <artifactId>persistence-unit</artifactId>
                            <bundleDir>lib</bundleDir>
                        </jarModule>

                        <-- I added these to get the deployment working -->
                        <jarModule>
                            <groupId>org.apache.shiro</groupId>
                            <artifactId>shiro-core</artifactId>
                            <bundleDir>lib</bundleDir>
                        </jarModule>
                        <jarModule>
                            <groupId>org.slf4j</groupId>
                            <artifactId>slf4j-api</artifactId>
                            <bundleDir>lib</bundleDir>
                        </jarModule>
                    </modules>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>persistence-unit</artifactId>
        </dependency>
        <dependency>
            <!-- ... -->
            <type>war</type>
        </dependency>
        <dependency>
            <!-- ... -->
            <type>ejb</type>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
        </dependency>
    </dependencies>
</project>

And for the persistence unit:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <artifactId>persistence-unit</artifactId>
    <packaging>jar</packaging>

    <parent>
        <groupId>com.example</groupId>
        <artifactId>project</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.jboss.spec</groupId>
            <artifactId>jboss-javaee-6.0</artifactId>
            <type>pom</type>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
        </dependency>
    </dependencies>
</project>

Solution

  • Are there any guide lines for what should be put in the library directory, and is my solution generally acceptable?

    You've pretty much nailed it, JARs that should be available to all the EAR modules should go here.

    Why aren't the libraries in the root of the ear available to the jars in the lib directory?

    It usually works the other way round, the JARs in the lib folder are available to the ones in the root. However, I believe you can achieve this by using <includeInApplicationXml>:

    <jarModule>
        <groupId>org.nisse</groupId>
        <artifactId>hue</artifactId>
        <includeInApplicationXml>true</includeInApplicationXml>
    </jarModule>
    

    Why doesn't maven figure this out automatically?

    I assume you mean that maven doesn't automatically place all transitive dependencies in lib? I believe it should do, and does - can you show the relevant portion of your POM perhaps?

    Edit: Your EAR module should only reference the EJB JARs and WARs as dependencies. Any transitive dependencies should be included in the EAR automatically, at top level by default - this can be overridden with the <defaultLibBundleDir> tag in the ear-plugin <configuration>:

    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-ear-plugin</artifactId>
    <version>2.7</version>
    <configuration>
        <defaultLibBundleDir>lib</defaultLibBundleDir>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
            </manifest>
        </archive>
        <modules>
           ... etc.
    

    Also the <archive>/<addClasspath> section should ensure that the MANIFEST classpath is set correctly. Perhaps this is exactly what you're missing?

    Cheers,