Lab - Deploying a POJO as an EJB3 Entity Bean

Pete Bennett (pbennett@jboss.com)
9 November 2006

This lab will show you how easy it is to take an existing POJO that simply represents one of your business objects and to deploy it as an EJB3 Entity Bean using annotations. Once this is done, your business objects will persist in a database and be searchable.

The POJO Base

The example is based on a very simple class. org.jboss.tutorial.entity.bean.Customer contains a standard Java class which defines a business object with four JavaBean style properties and accessors representing its state (a first name, a last name, a phone number and an ID for the Customer). Note that there is nothing special about this class - it is very simple Java.

org.jboss.tutorial.entity.bean.CustomerManagerBean is an EJB3 Stateless Session Bean that implements the org.jboss.tutorial.entity.bean.CustomerManager interface and provides a set of operations to interact with instances of Customer. In many ways CustomerManagerBean is reminiscent of an EJB2 Home interface but not that it is implemented as a pure Java interface. We will not recap how to expose business methods in a Stateless Session Bean as that was covered in the first lab.

Deploying as an EJB3

The Entity Bean EJB

It is very straightforward to create an Entity Bean in EJB3. You simply create a Java class that follows a simple set of conventions, add some annotations to your bean class to indicate to the EJB3 container your intentions and you’ve created a Entity bean.

The javax.persistence.Entity annotation marks a class as being an Entity Bean (in actual fact a Java Persistance Bean which might run in or outside a JEE container but we will ignore this distinction for the moment). This annotation does not take any arguments and can be added to a class using the syntax @Entity just before the class definition in the .java file.

TASK1: Import the Entity annotation class and add the Entity annotation to Customer.java.

In order to function well with databases, persistent objects should have a unique identifier, or primary key. It is good practice to make this identifier a non-semantically loaded one (i.e. not to base it on the last name but rather on a meaningless ID). Customer already includes a field called id which is perfect for our purposes. The javax.persistence.Id is used to indicate the field in an Entity that correponds to the primary key. This annotation does not take any arguments and can be added to a class using the syntax @Id just before the getter method definition corresponding to the property holding the primary key value in the .java file.

TASK2: Import the Id annotation class and add the Id annotation to Customer.java, specifying id as the property holding the primary key.

This is all you need to do to enable your POJO to be persisted. Again, EJB3 remove much of the pain of uneccesary configuration by using "smart defaults". So, when a Customer Object is persisted to a remote database it will be stored in a table called CUSTOMER and each of the properties will be mapped to a column with the same name as the property and the appropriate data type.

This is very convenient but sometimes you want more control over the mapping between the POJO and the database. In this case, you can use configuration by exception to configure just the things you wish to differ from the defaults.

For example, the javax.persistence.Column annotation is used to override the default name of the column in the database to which a given field will be persisted. This annotation takes a single argument which is the name of the database column to which a property should be mapped using the following pattern: @Column(name="COLUMN_NAME").

TASK3: Import the Column annotation class and add the Column annotation to Customer.java, specifying that the phone property should be stored in a column called "PHONE_NUMBER".

EntityManager and the CustomerManagerBean

EJB3 (again, more precicesly the Java Persistence API) introduces the javax.persistence.EntityManager to provide a generic mechanism with which to interact with persistent POJOs such as the Entity Bean we have just created. It is often more convenient to create a specific Java interface that is appropriate to the domain objects being used in a given project. The org.jboss.tutorial.entity.bean.CustomerManager is an example of such an interface which provides methods allowing for the creating, finding/searching, and deleting of Customer objects.

In an EJB3 environment such interfaces are realised in concrete Stateless Session Bean implementations such as org.jboss.tutorial.entity.bean.CustomerManagerBean. If you investigate this class you will see that it declares a member variable of type EntityManager which is apparently never initialised but is made liberal use of in methods such as createCustomer

One of the very nice new features of EJB3 is the concept of Inversion of Control (IoC) which allows the use of annotations to indicate the container what resources you would like it to automatically inject into your classes when they are required.

Instead of having to initialise an EntityManager by hand, the javax.persistence.PersistenceContext annotation is used to indicate which datasource we want to use and to automatically configure and inject an appropriate instance of EntityManager. This annotation takes a single argument which is the name of the persistence context column we wish to inject an EntityManager for using following pattern: @PersistenceContext(name="context-name").

TASK4: Import the PersistenceContext annotation class and add the PersistenceContext annotation to CustomerManagerBean.java, specifying that an EntityManager instance should be injected configured for the persistence context "lab-entity-demo4".

EntityManager provides a number of methods for interacting with persistence sources. One convenient method is Object EntityManager.find(Class entityClass, Object primaryKey) which takes a Class and a unique ID and returns the corresponding Object

TASK5: edit CustomerManagerBean to fix the findCustomer(int id) method so that instead of returning null it uses the EntityManager.find method to return the Object of class Customer.class with the corresponding int as a primary key.

The EJB container needs to understand how it should connect the "lab-entity-demo4" persistence context to the underlying data source. This is done via the persistence.xml file which is bundled into the deployed jar file with our Entity and Session bean. We will hook this persistence context up to the DefaultDS deployed with JBoss AS which is a Hypersonic instance for demo purposes.

TASK6: edit resources\META-INF\persistence.xml so that the "lab-entity-demo4" persistence context points to java:/DefaultDS

Running the Example

Make sure JBoss is running and then open a command prompt in the src\build directory and run "ant ejbjar". This compiles the code and then JARs it into a file called lab-entity-demo4.jar. If you investigate this file, you will note that it contains only the simple persistence.xml config and the three class files we have just annotated. This command also deploys the file by copying it to the JBoss deploy directory. JBoss scans the file automatically and discovers and deploys our new EJBs. If you look at the output from the running JBoss instance you will see confirmation that it has discovered a EJBs in the JAR file and deployed them sucessfully.

Open a command prompt in the src\build directory and run "ant runCreate". This compiles and runs the code in the org.jboss.tutorial.entity.client.ClientCreate class which creates five new Customer objects on the client-side and then uses CustomerManagerBean to persist them to a database on the server. In a real-world environment these objects would now persist over restarts of the JBoss AS environment (the DefaultDS is cleaned out on restarts). It then uses the findAllCustomers method to iterate over the saved Customer objects.

Open a command prompt in the src\build directory and run "ant runFind". This compiles and runs the code in the org.jboss.tutorial.entity.client.ClientFind class which searches for the Customer with id=3 and all Customer objects with surnames that start with "S" (Burr Sutter and Stan Silvert).

Open a command prompt in the src\build directory and run "ant runDelete". This compiles and runs the code in the org.jboss.tutorial.entity.client.ClientFind class which deletes the Customer with id=2 (Stan Silvert). Now rerun "ant runFind" and only Burr Sutter will appear

Conclusion

In this lab we have seen how easy it is to use EJB3 annotations to make an existing POJO business object into an Enterprise class database persistented in a J2EE container and again how EJB3's use of sensible defaults coupled with annotations remove much or all of the need for complex, unwieldy XML configuration files.