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

11,783

Solution 1

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,

Solution 2

I won't comment on the configuration of Maven, but merely where libraries should go.

There're two main mechanisms to share libraries amongst an EAR's modules - Bundled Libraries (described in EE.8.2.1 in the Java EE 6 specification) and Installed Libraries (EE.8.2.2).

Installed Libraries are installed separately from an EAR and therefore are shared amongst many EARs on an application server.

Bundled Libraries may be installed in lib (the default library directory), a directory specified by the library-directory element of an EAR's deployment descriptor and/or in any directory to be referenced with the Class-Path manifest header of a module (or a jar referenced by a module that in turn defines a transitive library).

My understanding of the Java EE 6 spec is that Class-Path can reference any library anywhere in an EAR, but the content of the jar becomes then a non-Java EE module. It means that persistence.xml is not considered upon deployment and potential persistence contexts defined in the file won't take effect at runtime.

In your case, persistence-unit.jar seems to contain persistence unit configurations and to make them available to the other modules it should be placed in the lib directory. The other two jars - shiro-core.jar and slf4j-api.jar - can be anywhere in the EAR (including the lib directory for a simple deployment - no need to have Class-Path element in any of the referencing libraries/modules).

Wrapping it up, to ease deployment have your libraries in the lib directory unless Class-Path is used and points to another directory. In this case, you'd rather check out whether the referencing jar file is not a Java EE jar with a persistence unit definition as it won't get deployed properly (and PUs won't be available to the modules).

Solution 3

This article has a great table explaining things:

Table 2 A standard archive may load classes either packaged inside it or from any other archives it is dependent on.

Module      Code Sources
EAR 
            All JARs in the /lib directory of the EAR
            Manifest Class-Path of any JARs in 1
EJB-JAR 
            EJB-JAR file itself
            JARs referenced by manifest Class-Path of EJB-JAR
            JARs referenced by manifest Class-Path of above JARs (in 2)
WAR 
            WEB-INF/classes
            JARs in WEB-INF/lib
            JARs referenced by manifest Class-Path of WAR
            JARs referenced by manifest Class-Path of JARs in 2 and 3
Share:
11,783
Simon Lindgren
Author by

Simon Lindgren

Updated on June 05, 2022

Comments

  • Simon Lindgren
    Simon Lindgren about 2 years

    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>
    
  • Simon Lindgren
    Simon Lindgren over 11 years
    Your assumption about question 3 is correct. I updated the question with the poms. Simplified, but hopefully enough and without removing the actual problem :)
  • Anders R. Bystrup
    Anders R. Bystrup over 11 years
    I've added more info to my answer, I hope that helps you a bit further - at least the addClasspath might be what you need. I am in doubt whether your issue is getting maven to actually include transient deps or just have them be available on the classpath. If the latter, I think this is just what you need. Cheers,