Thursday, May 29, 2014

Java EE7 and Maven project for newbies - part 4 - defining the ear module #javaee #java #maven #juniordevs


    Previous Post , Next Post

      We are resuming for the 4th part, our simple project currently has 
      • a web maven module (a war)
      • an ejb module (ejb)  holding our stateless session beans (EJB 3.1)
      • and a second (ejb) module holding our entity beans (JPA2) 
      but we are still missing the one to package them all, archive, which will be of 'ear' type  (aka Enterprise Archive)

       Defining our ear maven module

      As you can see in the image below, we create emtpy folder called sample-ear under the sample-parent. This folder needs to have a pom.xml file. Our new module needs to be correctly referenced in the  'modules'  section of the sample-parent\pom.xml.

      The main purpose of our ear maven module is to 'configure' the famous maven-ear-plugin, which is going to be invoked by maven and is going to produce our final deployable application.

      There 2 simple things we need to do, add configuration for the maven-ear-plugin, and add our 'internal' application dependencies on the ear module, so that it 'knows' which modules should look up. Let's have a look

      Inside the ear pom.xml

      This is the build, section make note on the following things
      • Remember as we did other modules, we have defined some basic common configuration for our plugin, in the 'parent' pom. Go back and have a look what is already there for you.
      • Watch out the 'defaultJavaBundleDir' this where we define where all the libraries (apart from the top-level modules that will reside in our ear, usually is  a sub-folder in the ear called 'lib'
      • What is a top level module? It is actually, the  jar(s), and wars that are going to be packaged in the ear, and are considered first level citizens,as you can see we define 2, the sample-web and the sample-services.
      • Watch out the 'skinnyWars' property. With this switch enabled, we enforce a certain pattern on packaging our third party libs, referenced from our war project. Simply put, our war archives are NOT going to include any external libraries we might define as dependencies under their WEB-INF\lib folder, instead all those libs,they are going to be packaged in the 'defaultJavaBundleDir' path on the ear level.

      The above configuration is not going to work, if we dont add the 'dependencies' section of our ear-pom.

      Make note of the following
      • the dependency element in this pom, needs the 'type' attribute.

      One good question you may have is, where the sample-domain (jar) module?

      Well this module, is not promoted as a top level element in our ear, because we are going to add it as a dependency on the sample-services module. So our services will hold a dependency on the module of the entity beans. (Sounds fair). So we need to update the pom.xml of our sample-services module.

      By doing that, the sample-services.jar is going to 'fetch' along the sample-domain.jar. By default (remember Maven is all about conventions), when we define a top level module to an ear,l ike the sample-services, it's dependencies are bundled automatically under the defaultJavaBundleDir lib of the ear! So when we package our ear, we will be expecting to see the sample-domain jar packaged.

      One more missing dependency

      After our first ' in app dependency between the services module and the entities module, we need another one. Our war module, (web layer) is going to use some of our services, but in order to being able to do it needs to have a dependency on the 'services' module. So we need to the pom.xml on the sample-web project, accordingly.

      Let's package our war.

      We are ready for now, our basic dependencies are set, our ear is configured, we just need to package. Under the sample-parent folder level on command line we just need to type

      mvn clean package

      We are done, let's check under the 'target' folder of the sample-ear module. Our final ear is ready, maven also creates the 'exploded' version of the ear, (it is, expanded in the image below). Notice our 2 top level ear elements, and how the sample-domain.jar is under the 'lib' folder of our ear. Also notice that some basic libraries like the javaee-api.jar are not included in the lib folder. Since we have added the provided in the pom. (see the final version of the xml).

      One last thing...skinny war(s) and MANIFEST.MF files

      Eventually, we could stop here, our final ear is ok and is going to work, but with all the above configuration, especially with our preference to create, skinny wars , we need to pay attention to a small detail. MANIFEST files are special descriptors within jars and wars, that are used by application servers on locating and class loading 'dependent' jars in the class path, within the ear.

      Our small problem resides in the MANIFEST.MF file of the sample-web.war. If we unpack the generated war file and we open with a text editor the MANIFEST.MF we will see is something like that.

       Can you spot the mistake? By default the MANIFEST.MF generated, is indicating a wrong path for one of our top-level ejb jars(sample-services). Our sample-services.jar is not place under the \lib within the ear, but is a top level element. So how are we going to create a correct MANIFEST?
      Eventually we need to fine tune a bit the maven-war plugin. We need to overwrite the default behaviour as specified in the parent pom, and specify a correct entry for this particular dependency. If you happen to have more than one, then you need to append all the jars that are top level elements in the configuration (make sure you do it properly, use a space between entries).So in the sample-war pom we need to add some configuration (extra) on top of the one applied. See the image below.

      There is an interesting stackoverflow issue, that you can read more about this, little trick or other potential workarounds in case you use skinny-wars.

      That's it, our ear is ready.


      You can find the final version for this post in this Git Tag.With this post, we are completing a first series of posts, starting from scratch, applying basic maven principles and creating some basic maven modules for a java enterprise application. Feel free to re-use this example and extend it in order to meet your own needs. It is by far complete in terms of covering all your needs, but it is a solid example on getting starting, thinking and configuring in Maven.

      I am going to expand on this example, adding more modules and using more features of maven in future posts.


      1. Thank you so much for this great post

      2. Thanks for such a great piece of information,its really good one. When i ran the application with Maven i got some errors. Test cases got failed.

        Pasting the error statements below.

        INFO [] JBAS015950: WildFly 8.2.0.Final "Tweek" stopped in 31ms
        Running gr.javapapo.jpatests.PostgreSQLTest
        Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.016 sec <<< FAILURE! - in gr.javapapo.jpatests.PostgreSQLTest
        testGetUser(gr.javapapo.jpatests.PostgreSQLTest) Time elapsed: 0.01 sec <<< ERROR!
        java.lang.NullPointerException: null
        at gr.javapapo.jpatests.PostgreSQLTest.init(

        Running gr.javapapo.jpatests.UserEntityTest
        Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.015 sec <<< FAILURE! - in gr.javapapo.jpatests.UserEntityTest
        testGetUser(gr.javapapo.jpatests.UserEntityTest) Time elapsed: 0.008 sec <<< ERROR!
        java.lang.NullPointerException: null
        at gr.javapapo.jpatests.UserEntityTest.init(

        Results :

        Tests in error:
        PostgreSQLTest.init:40 NullPointer
        UserEntityTest.init:40 NullPointer

        Tests run: 3, Failures: 0, Errors: 2, Skipped: 0

      3. Your kind time and help would be greatly appreciated.

      4. gr.javapapo.jpatests.UserEntityTest Time elapsed: 4.676 sec <<< ERROR!
        java.lang.RuntimeException: Could not invoke deployment method: public static org.jboss.shrinkwrap.api.spec.WebArchive gr.javapapo.jpatests.UserEntityTest.createDeployment()
        at org.jboss.shrinkwrap.api.asset.ClassLoaderAsset.(
        at org.jboss.shrinkwrap.api.asset.ClassLoaderAsset.(
        at org.jboss.shrinkwrap.impl.base.container.WebContainerBase.addAsWebInfResource(
        at gr.javapapo.jpatests.UserEntityTest.createDeployment(

      5. The property 'defaultJavaBundleDir' has been replaced by 'defaultLibBundleDir' (for goal ear:ear).

        thanks for your tutorial. this really saved my life! thanks.

      6. if maven-ear-plugin gives your an error "[INFO] Failed to initialize ear modules Embedded error: Unknown artifact type[zip]"

        in windows 10, open cmd, cd root directory of your the project first, then type "mvn dependency:tree" in the cmd, to find transitive dependencies that has conflict with marven-ear-plugin.

        +- means com.sun.xml.wssamples

        change ear pom:put exclusion in your dependency

        artifactId: samples