Enterprise Java Bean / EJB 3.1 Testing using Maven and embedded Glassfish

January 1st, 2011 by

Are you playing around with the shiny new 3.1 EJB API?

Using Maven for your Java projects?

Need an easy way to write and execute tests for your EJBs that depends on an Java Application Server?

No problem using Maven Archetypes, the Maven EJB Plugin and the GlassFish embedded Application Container..

 

Prerequisites

For the following tutorial we’re going to need an installation of Maven and of course – the Java Development Kit!

Project Setup

We want to make our life as easy as possible and there is an interesting archetype for ejb-components available: org.codehaus.mojo.archetypes:ejb-javaee6 ..

  • At first we’re creating a new project using Maven Archetypes (choose “ejb-javaee6” and EJB version 1.3 !!) using your IDE with a Maven plugin installed or via console like this
    mvn archetype:generate
    [INFO] Generating project in Interactive mode
    [INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
    Choose archetype:
    [..]
    242: remote -> ejb-javaee6 (Archetype for an EJB package using Java EE 6.)
    [..]
    Choose a number: 98: 242
    Choose version:
    1: 1.0
    2: 1.0.1
    3: 1.0.2
    4: 1.1
    5: 1.2
    6: 1.3
    Choose a number: 6: 6
    [.. etc ..]
  • Now we just need to add the dependency for the embedded GlassFish server and the Java repository to our  pom.xml. It is important to add the dependency for glassfish-embedded-all as the first dependency to the list (-> Troubleshooting)!
  • Finally our pom.xml should look like this one
    <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>
     <groupId>com.hascode.tutorial</groupId>
     <artifactId>ejb-tutorial</artifactId>
     <version>0.0.1</version>
     <packaging>ejb</packaging>
     <name>hasCode.com ejb-tutorial EJB</name>
     
     <properties>
       <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
     
     <dependencies>
       <dependency>
         <groupId>org.glassfish.extras</groupId>
         <artifactId>glassfish-embedded-all</artifactId>
         <version>3.0</version>
         <scope>test</scope>
       </dependency>
       <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.8.1</version>
         <scope>test</scope>
       </dependency>
       <dependency>
         <groupId>javax</groupId>
         <artifactId>javaee-api</artifactId>
         <version>6.0</version>
         <scope>provided</scope>
       </dependency>
     </dependencies>
     
     <build>
       <plugins>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <version>2.3.2</version>
           <configuration>
             <source>1.6</source>
             <target>1.6</target>
             <compilerArguments>
               <endorseddirs>${endorsed.dir}</endorseddirs>
             </compilerArguments>
           </configuration>
         </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-ejb-plugin</artifactId>
           <version>2.3</version>
           <configuration>
             <ejbVersion>3.1</ejbVersion>
           </configuration>
         </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-dependency-plugin</artifactId>
           <version>2.1</version>
           <executions>
             <execution>
               <phase>validate</phase>
               <goals>
                 <goal>copy</goal>
               </goals>
               <configuration>
                 <outputDirectory>${endorsed.dir}</outputDirectory>
                 <silent>true</silent>
                 <artifactItems>
                   <artifactItem>
                     <groupId>javax</groupId>
                     <artifactId>javaee-endorsed-api</artifactId>
                     <version>6.0</version>
                     <type>jar</type>
                   </artifactItem>
                 </artifactItems>
               </configuration>
             </execution>
           </executions>
         </plugin>
       </plugins>
       <finalName>ejb-tutorial</finalName>
     </build>
     
     <repositories>
       <repository>
         <id>maven2-repository.dev.java.net</id>
         <name>Java.net Repository for Maven</name>
         <url>http://download.java.net/maven/2/</url>
         <layout>default</layout>
       </repository>
       <repository>
         <id>maven2-repository.dev.java.net.glassfish</id>
         <name>Java.net Repository for Maven</name>
         <url>http://download.java.net/maven/glassfish/</url>
       </repository>
     </repositories>
    </project>
  • Create a dumb JavaBean named UserBean in the package com.hascode.tutorial.ejb_tutorial.bean
    package com.hascode.tutorial.ejb_tutorial.bean;
     
    public class UserBean {
     private Long    id;
     
     private String    firstName;
     
     private String    lastName;
     
     public Long getId() {
     return id;
     }
     
     public void setId(Long id) {
     this.id = id;
     }
     
     public String getFirstName() {
     return firstName;
     }
     
     public void setFirstName(String firstName) {
     this.firstName = firstName;
     }
     
     public String getLastName() {
     return lastName;
     }
     
     public void setLastName(String lastName) {
     this.lastName = lastName;
     }
    }
  • Create the EJB to deliver a list of all available UserBeans named UserEJB .. a simple @Stateless annotation is enough to make this bean a stateless Enterprise Java Bean ..
    package com.hascode.tutorial.ejb_tutorial.bean;
     
    import java.util.ArrayList;
    import java.util.List;
     
    import javax.ejb.Stateless;
     
    @Stateless
    public class UserEJB {
     public List<UserBean> findAll() {
     List<UserBean> users = new ArrayList<UserBean>();
     UserBean user = new UserBean();
     user.setFirstName("Alfred");
     user.setLastName("Newman");
     user.setId(1l);
     
     UserBean anotherUser = new UserBean();
     anotherUser.setFirstName("Albert");
     anotherUser.setLastName("Einstein");
     anotherUser.setId(2l);
     
     users.add(user);
     users.add(anotherUser);
     return users;
     }
    }
  • That is all we need for now .. now let’s do some testing …

Testing in the embedded EJB Container

Now that we’ve got all our classes together we should test their functions and the wiring in the EJB container. This is where the new embeddable EJB Container API saves our lives.

  • We’re writing a new test case named UserEJBTest in src/test/resources
    package com.hascode.tutorial.ejb_tutorial.bean;
     
    import static org.junit.Assert.assertEquals;
    import static org.junit.Assert.assertNotNull;
     
    import java.util.List;
     
    import javax.ejb.embeddable.EJBContainer;
    import javax.naming.Context;
    import javax.naming.NamingException;
     
    import org.junit.AfterClass;
    import org.junit.BeforeClass;
    import org.junit.Test;
     
    public class UserEJBTest {
     private static EJBContainer    ejbContainer;
     private static Context        ctx;
     
     @BeforeClass
     public static void setUp() {
     ejbContainer = EJBContainer.createEJBContainer();
     ctx = ejbContainer.getContext();
     }
     
     @AfterClass
     public static void tearDown() {
     ejbContainer.close();
     }
     
     @Test
     public void testFindAll() {
     try {
     UserEJB userEJB = (UserEJB) ctx.lookup("java:global/classes/UserEJB!com.hascode.tutorial.ejb_tutorial.bean.UserEJB");
     assertNotNull(userEJB);
     List<UserBean> users = userEJB.findAll();
     assertNotNull(users);
     assertEquals(2, users.size());
     } catch (NamingException e) {
     throw new AssertionError(e);
     }
     }
    }
  • So what’s happening here? First we’re starting the embedded EJB Container, lookup the UserEJB via JNDI and assert that the user information we were looking for is present via the EJB.
  • If you’re not sure what the corresponding JDNI name for your bean is, take a look at the console output on the EJB container startup .. when the UserEJB is registered the following helpful information shows you available JNDI names
    INFO: Portable JNDI names for EJB UserEJB : [java:global/classes/UserEJB, java:global/classes/UserEJB!com.hascode.tutorial.ejb_tutorial.bean.UserEJB]
  • The test should run without errors

Download Sources

I have put the sources for the examples here on Bitbucket .. you may download it there or check it out using

hg clone http://bitbucket.org/hascode/ejb-3.1-embedded-tutorial

Troubleshooting

  • java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/ejb/embeddable/EJBContainerI got this error when glassfish-embedded-all was not the first dependency in the dependencies list in my pom.xml – changing the order helped ..
  • java.lang.AssertionError: javax.naming.NamingException: Lookup failed for ‘java:global/classes/UserEJB!com.hascode.tutorial.ejb_tutorial.bean.UserEJB’ in SerialContext  [Root exception is javax.naming.NameNotFoundException: classes]To fix this error, initialize the EJBContainer instance in the unit test like this (thanks to Ian Smith for mentioning)
    Map properties = new HashMap();
    properties.put(EJBContainer.MODULES, new File("target/classes"));
    ejbContainer = EJBContainer.createEJBContainer(properties);

Alternatives

There are some alternative frameworks that I haven’t tested yet

  • jeeunit – sounds really nice
  • arquillian – alpha version but I think the JBoss guys are going to catch up fast :)

Resources

Tags: , , , , , , , , , , , , , , , ,

8 Responses to “Enterprise Java Bean / EJB 3.1 Testing using Maven and embedded Glassfish”

  1. Ian Smith Says:

    Hmm, nice post, once again this is posted as working code – I must really have a problem somewhere!

    To make this work for me, I have to change your test setup code to something like:

    Map properties = new HashMap();
    properties.put(EJBContainer.MODULES, new File(“target/classes”));
    properties.put(“org.glassfish.ejb.embedded.glassfish.installation.root”, “glassfish”);
    ec = EJBContainer.createEJBContainer(properties);

    If I try to use your code as-is, I get a stream of WebDeployer NPEs. Strange how the simple method seems to work for others . . . explanations welcome!

    Ian.

  2. Ian Smith Says:

    OK I think it is because of my glassfish config, I am using an embedded derby too . . .
    Pardon me! Ian.

  3. micha kops Says:

    Thanks for mentioning your problem :) One early build of mine failed without the definition of EJBContainer.MODULES creating the embedded container and I found the same solution for this problem on stackoverflow but I’m not sure yet why it failed ..

    Another interesting alternative perhaps is the jeeunit project but I haven’t tested it yet :)

  4. Viggo Navarsete Says:

    Hi,

    I’ve been struggling lately getting some existing EJB’s to work using embedded GlassFish. It turns out it must be because they implement an interface. I tried to download your “Enterprise Java Bean/EJB 3.1 Testing using Maven and embedded Glassfish” and modify it to let the EJB implement an interface, and even your test fail then.
    Do you have any experience testing EJB’s which implement an interface?
    I have a project at work where we have used OpenEJB in the past to test the EJB’s, but for the past 2-3 months, the 3.2-SNAPSHOT hasn’t been working.So, I though I should give embedded Glassfish a try, but as I describe, I have a hard time getting them tested because most of them implement an interface! I’ve seen this issue, which I _think_ can be related: http://java.net/jira/browse/GLASSFISH-16547

    Any clue or any experience?

    Best regards,
    Viggo

  5. micha kops Says:

    Perhaps you need to modify the JNDI lookup in the test class … I have modified my tutorial like this: UserEJB implements the interface UserEJBRemote where I just used extract method pattern ..

    public class UserEJB implements UserEJBRemote {..}
    public interface UserEJBRemote {
    public abstract List findAll();
    }

    Now I changed the ctx.lookup in my test class to this one:

    UserEJBRemote userEJB = (UserEJBRemote) ctx.lookup("java:global/classes/UserEJB!com.hascode.tutorial.ejb_tutorial.bean.UserEJBRemote");

    Is this a help? Perhaps JBoss Arquillian is also worth a look .. it’s an early version but has some nice features :)

  6. xmoulin Says:

    Little mistake at the end of the class UserEJB, add ‘user’ twice.
    users.add(user);
    users.add(anotherUser);

    :-)
    Xavier.

  7. micha kops Says:

    thanks for mentioning! I’ve fixed the typo :)

  8. JEE 6 – Asynchronous methods calls example | Andrei Ribas' Software Development Blog! Says:

    [...] I want to thank Micha Kops for this blog post, it helped me a lot to create my example running on Junit tests using an embedded Glassfish server. [...]

Leave a Reply

Please leave these two fields as-is:

Protected by Invisible Defender. Showed 403 to 81,008 bad guys.

Search
Categories