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 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.
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".
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
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
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.