J3 Limited
 
Google
WWW J3Ltd
 
EJB 3.0 Entity Beans Quick Overview

Introduction

The EJB 3.0 specification, available from Sun Microsystems introduces many changes to the way entity beans are coded by an application developper. This article provides a brief overview of how to code EJB 3.0 entity beans. The target audience is for experienced EJB 2.1 or EJB 3.0 developers who would like a refresher of EJB 3.0 entity beans.

The EJB 3.0 API is part of the "Persistence API". The specification document called "JSR 220: Enterprise JavaBeansTM,Version 3.0, Java Persistence API" is available from java.sun.com. This document clearly states that the persistence API can be used outside J2EE containers. Hence we can expect web applications as well as fully fledged JEE5 application to make use of the facilities offered in the EJB 3.0 specification.

The Entity Class

The entity class is annotated with @Entity. If the bean data is to be available remotely, the class must implement java.io.Serializable.

Transient Fields

Fields that are not persisted should be annotated as @Transient.

Entity Fields

The fields should be declared "private" (but can be protected). Bean accessor methods are used to get and set the fields.

The field datatypes worth noting:

  • Java primitive types (int, short, float....)
  • Primitive type wrappers, including java.sql.Date, java.sql.Timestamp and java.sql.Time.
  • String
  • enums
  • other entity types or collections of entity types.

Collections of entities use the java.util.collection interfaces:

  • java.util.Collection
  • java.util.List
  • java.util.Map

It is usaually a good idea to use the java generic interfaces when a field is a collection.

Primary Key(s)

Ideally the entity has a single field that represents the primary key. A primary key can be one of the following types:

  • Primitve type
  • Primitive wrapper class
  • java.sql.Date or java.util.Date

A simple primary key is annotated with @Id, on the getter.

Composite keys should be enclapsulated in a java class. Such a class must implement java.io.Serializable and have the following methods:

  • public no-arg constructor
  • if no getters and setters are used, the properties must be public or protected.
  • equals() and hashcode() methods must be implemented.

Composite keys are annotated with @EmbeddedId or @IdClass

Accessor Methods

The entity field get and set can have some code added, for example to perform some validation, however, it should be noted that this is not reccomended, as the order in which these methods are called is not defined.

Entity Relationships

An entity's field (which is another entity class, or collection of entities) can be annotated, on the getter, as:

  • @OneToOne
  • @OneToMany
  • @ManyToOne
  • @ManyToMany

The reverse path from the entity to the owning one (bidirectional relationship) uses the same annotations as above, with the mappedBy element which names the field name in the owning entity. The reverse path is not always there (unidirectional relationship).

Lifecycle Callabcks

Some callback methods can be coded in an entity, and annotated so that the container can determine that they exist. The annotations are:

@PrePersist: the method can be used to validate the data and throw an exception is there is an error.
@PostPersist: any generated primary key values are available
@PreRemove
@PostRemove
@PreUpdate
@PostUpdate
@PostLoad

The callback method is defined in the entity as void methodname().

It is possible to code callbacks in listener classes, in which case the callback is of the form:

void methodname(Object entityForCallback)

The entity listener class is annotated on the Entity class:

@EntityListeners(MyListenerClassName.class)

Using Entities

The interface javax.presistence.EntityManager is used to interact with the database, and work with entity EJB's.

An Entity Manager instance is declared with the @PersistenceContext annotation:

@PersistenceContext EntityManager em;

Once declared it can be used to perform operations on the database, queries can be entered in eirther native SQL or EJB sql.

The transaction can span one or more database opterations, the behaviour is determined at the time the EntityManager is created.

public enum PersistenceContextType {
  TRANSACTION,
  EXTENDED
}

The EXTENDED value means that the transaction is not commited until the EntityManager is closed. The annotation used to define an EXTENDED transaction entity manager is:

@PersistenceContext(type=PersistenceContextType.EXTENDED)
EntityManager em;

Entity managers can also be created using a JNDI lookup.

To the unitiated , getting entity managers to work with EJB's can be fraught with problems. The following has been found to work using JBoss and MySQL:

In the stateless EJB class that wants to access the entity EJB:

@PersistenceContext(unitName="shoestringPU")
EntityManager em;

The EJB's are packaged in an archive. In the META-INF folder of the archive is a file called persistence.xml, its contents are as follows:

<?xml version="1.0" encoding="UTF-8"?>
<persistence>
  <persistence-unit name="shoestringPU">
    <jta-data-source>java:/ShoestringDS</jta-data-source>
    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
    </properties>    
  </persistence-unit>
</persistence>

A datasource has been defined in JBoss called ShoestringDS. It's done by deploying the shoestring-ds.xml file in the deploy folder of the default server. The contents of this file are below:

<datasources>
 <local-tx-datasource>
  <jndi-name>ShoestringDS</jndi-name>
  <connection-url>jdbc:mysql://192.168.0.6:3306/shoestring</connection-url>
  <driver-class>com.mysql.jdbc.Driver</driver-class>
  <user-name>user</user-name>
  <password>password</password>
 </local-tx-datasource>
</datasources> 

The jdbc driver for MySQL has been copied to the lib folder of the default server folder in JBoss.

Queries

The EntitiyManager interface supplies several query methods which return a javax.presistence.Query instance. In essence three types of queries can be defined:

  • Named Query: the query is defined in the entity class' annotation, the query can be ejb ql or sql.
    @NamedQuery(name="queryName", query="ejb ql query")
  • Native Query: the query uses sql native to the database
  • Query: the query uses EJB QL.

Note: In most cases it is a good idea to use EJB QL queries. Native sql queries inevitably end up making use of something which is not only specific to the DBMs being used, but also the the particular database naming scheme/layout. It is therefore more likely to be difficult to code against a test database and move to the live database (and vice versa) without any effort.

Mapping Java Names To DBMS Names

An entity class is mapped to a database table. The @Entity annotation does this. Optionally the @Table() annotation can be used to specify the table name, catalog, schema and other database specific details.

A class property is mapped to a database column. Unless the column name in the database is not the same as the column name, no annotation is necessary. Otherwise the @Column(name="dbms column name") annotation can precede the PropertyType getMyPropertyName() method.

For primary keys, the Primary key getter is preceded by @Id. If the primary key is generated, then @Id(generate = GeneratorType.AUTO) is entered.

More details and very good examples can be found the the "JSR 220: Enterprise JavaBeansTM,Version 3.0, Java Persistence API" document available from java.sun.com. Chapter 9, "Metadata For Object/Relational Mapping".

  Copyright © 2006 J3 Ltd Permission is granted to reproduce material on this page, on the condition that a reference to "WWW.J3Ltd.com" is given as the source of the material.