Enterprise Java Bean / EJB 3.1 Testing using Maven and embedded Glassfish
January 1st, 2011 by Micha KopsAre 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..
Contents
Prerequisites
For the following tutorial we’re going to need an installation of Maven and of course – the Java Development Kit!
- Java Development Kit (JDK) 6
- Maven >=2
- A text editor or IDE of choice
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; // getter, setter ommitted.. }
- 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/EJBContainer“ – I 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);
Alternative: Arquillian
Meanwhile, I’ve switched to using Arquillian for testing Java EE applications. If you’re interested, please feel free to have a look at the following tutorials of mine:
- Arquillian Tutorial: Writing Java EE 6 Integration Tests and more..
- Arquillian Transaction Extension: Transaction Rollback for your Java EE Integration Tests
- Java EE: Setting up and Testing Form-Based JDBC Authentication with Arquillian and Maven
- Marrying Java EE and BDD with Cucumber, Arquillian and Cukespace
Resources
- Java Community Process: JSR 318: Enterprise Java Beans 3.1
- Maven EJB Plugin Website
- GlassFish Project Website
- Oracle.com: Java Naming and Directory Interface (JNDI)
- Oracle.com: Code-Snippet – JNDI
- Sun Blog: A Sampling of EJB 3.1
- Antonio Goncalves: Beginning Java™ EE 6 Platform with GlassFish™ 3
- Oracle.com: Using the EJB 3.1 Embeddable API with Embedded Enterprise Server
- EJBContainer JavaDocs
- CTP Java Competence: Unit Testing EJBs and JPA with Embeddable GlassFish
- jeeunit Project Website
- JBoss.org: Arquillian Documentation. Getting started
Article Updates
- 2015-03-21: Links to Arquillian articles added.
Tags: application server, arquillian, bean, ejb, embedded, enterprise java bean, example, glassfish, java ee 6, jee, jeeunit, jndi, jsr-318, junit, maven, testing, tutorial
January 4th, 2011 at 12:04 pm
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.
January 4th, 2011 at 1:51 pm
OK I think it is because of my glassfish config, I am using an embedded derby too . . .
Pardon me! Ian.
January 4th, 2011 at 1:59 pm
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 :)
May 31st, 2011 at 4:49 pm
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
May 31st, 2011 at 6:27 pm
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 :)
December 24th, 2011 at 10:06 pm
Little mistake at the end of the class UserEJB, add ‘user’ twice.
users.add(user);
users.add(anotherUser);
:-)
Xavier.
December 25th, 2011 at 11:46 pm
thanks for mentioning! I’ve fixed the typo :)
March 22nd, 2014 at 1:02 pm
[...] 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. [...]