Simplifying EJB Development with EJB 3.0


By Debu Panda

Enterprise JavaBeans (EJB) has been criticized by many developers for its complexity. EJB 3.0, being worked under JSR-220 of the Java Community Process, is designed to simplify development of applications and standardize the persistence API for the Java platform.

In this article, I will explain how EJB 3.0, a full implementation of which is available in Oracle Application Server EJB 3.0 Preview, simplifies the programming model for EJB and defines a simple API for persistence.

Complexities with EJB 2.x

The current EJB 2.x model is overly complex for a variety of reasons:

  • The current EJB model requires you to create several component interfaces and implement several unnecessary callback methods.
  • The component interfaces require implementation of EJBObject or EJBLocalObject and handling of many unnecessary exceptions.
  • The EJB deployment descriptor is complex and error prone.
  • The container-managed persistence, being based on the EJB model, is overly complex to develop and manage. Several basic features are missing--such as a standard way to define a primary key using a database sequence. The EJBQL syntax is very limited.
  • EJB components are not truly object-oriented, as they have restrictions for using inheritance and polymorphism.
  • Developers cannot test EJB modules outside an EJB container and debugging an EJB inside the container is a nightmare.
  • Looking up and invoking an EJB is a complex task. Detailed knowledge of JNDI is required for even the most basic use of an EJB in your application.

Simplifying Developers view

If you’ve ever developed an EJB with the current spec, you probably realize how difficult it is develop a simple EJB such as HelloWorld EJB. Even for this simple task, you need at least two interfaces: a bean class and a deployment descriptor. IDEs such as Oracle JDeveloper and utilities like XDoclet simplify these mundane tasks; however, it is still the responsibility of developers to compile these classes and package the deployment descriptor before the EJB can be deployed in the container of choice.

EJB 3.0 is designed to address the complexities of the current EJB model by:

  • Removing need for unnecessary interfaces and implementation of callback methods
  • Using metadata annotations instead of deployment descriptors
  • Using regular Java classes as EJBs and regular business interfaces for EJBs

Metadata Annotations

EJB 3.0 depends heavily on metadata annotations. Metadata annotation was standardized under JSR 175 and is part of J2SE 5.0. Annotation is a type of attribute-oriented programming and is similar to Xdoclet in its function; however, unlike XDoclet, annotations are compiled into the classes (depending upon what the @Retention is set to) by the Java compiler at compile-time. Overall, the goal of EJB 3.0 is to simplify development by supporting the use of metadata annotations to generate several artifacts (such as interfaces), as well as to replace deployment descriptors.

From a developer’s point of view, annotations are modifiers - just like public - and can be used in classes, fields, methods, parameters, local variables, constructors, enumerations and packages. You can use annotations in your Java code by specifying attributes that can be used for generating code, documenting code, or providing special services such as enhanced business-level security or special business logic during runtime. If you want to know details about annotations you can refer to Making the Most of Java's Metadata by Jason Hunter.

One major goal of J2EE 5.0 is to simplify development using annotations, so as you might expect, it includes its own set of annotations. Annotations are marked with @ as follows:

                         

  @Author("Debu Panda")
  @Bean
  public class MySessionBean
  
                      

Using POJOs and POJIs

In canonical terms, JavaBeans and interfaces are often referred to as Plain Old Java Objects (POJOs) and Plain Old Java Interfaces (POJIs), respectively. The EJB class and interface will now resemble POJO and POJI respectively. The unnecessary requirement of the artifacts like home interface is being removed.

You do not have to implement one of the EJB interfaces( SessionBean, EntityBean or MessageDrivenBean) in javax.ejb package. Instead, you can either use Stateless, Stateful, MessageDriven or Entity to annotate their bean class. For example, if you were to define a stateless EJB as HelloWorld, you’d define the EJB as follows:

                         

import javax.ejb.Stateless;
@Stateless
public class HelloWorldBean implements HelloWorld 
{
  public void sayHello(String name)
  {
    System.out.println("Hello "+name +" from your first EJB 3.0 component ...");
  }
}
                      

The interfaces for EJBs, either remote or local, do not have to implement EJBObject or EJBLocalObject. The bean class now implements the business interface for your EJB--in our example as in our example HelloWorldBean implements HelloWorld interface.

                         

import javax.ejb.Remote;
@Remote

public interface HelloWorld 
{
  public void sayHello(String name);
}
                      

If you look at the above code example, it is very clear that @Remote is used to mark the interface to be a remote interface. If needed, you may have remote as well as local interfaces for your EJB. Home interfaces are now optional even for Session Beans.

From the above example, you can clearly see that with EJB 3.0, many mundane tasks--such as creating deployment descriptors and implementing unnecessary callback methods– are now obsolete.

Removing need for Callback methods

EJB 2.1 and prior releases required implementation of several lifecycle methods such as ejbPassivate, ejbActivate, ejbLoad, ejbStore and so on for every EJB, even if they weren't needed from the functional aspect. For example, ejbPassivate is not required for a stateless session bean; nevertheless, you are required to implement that method in your bean class. As EJB 3.0 now resembles regular Java classes, implementation of these lifecycle methods has been made optional. You can now define lifecycle callback methods either in the bean class or as an external class. Any arbitrary methods can be marked as a callback method using annotation as in the following example:

                         

  @PostConstruct
    public void initialize() {
        items = new ArrayList();
    }
                      

Interceptors

The interceptors offer fine-grained control over the method invocation flow. You can use them on stateless session beans, stateful session beans, and message-driven beans. The interceptor may be either a method in the same bean class or an external class.

Annotations vs. deployment descriptors

As I mentioned previously, in EJB 3.0 annotations will replace deployment descriptors. Each attribute in the deployment descriptor has default values so you do not have to specify these attributes unless they want a value other than the default value. These values can be specified using annotations in the bean class itself.

The EJB 3.0 specification also defines a set of metadata annotations such as bean type, type of interfaces, resource references, transaction attributes, security, and so on. For example, if you want to define security settings for a particular EJB method, you can define the following in the bean class:

                         

 @MethodPermissions("user")
    public void sharedTask() {
        System.out.println("Shared admin/user method called");
    }
                      

Those nasty XML descriptors are now out of our way!

Simplifying Container Managed Persistence

CMP entity bean is getting a major overhaul in EJB 3.0 to make it compelling for developers: EJB 3.0 is adopting a lightweight persistence model like Oracle TopLink and Hibernate.

Entity beans are now POJOs and there no component interfaces are required for entity beans. Entity beans now support inheritance and polymorphism.

Following is the source code for a very simple entity bean:

                         

@Entity
@Table(name = "EMP")
public class Employee implements java.io.Serializable
{
   private int empNo;
   private String eName;
   private double sal;
   
   @Id
   @Column(name="EMPNO", primaryKey=true)
   public int getEmpNo()
   {
      return empNo;
   }

   public void setEmpNo(int empNo)
   {
      this.empNo = empNo;
   }

   public double getSal()
   {
      return sal;
   }

   ...


}

                      

If you look at the code, you will find that the bean class is a concrete class, not an abstract one such as CMP 2.x entity bean.

Here are few some major enhancements being made with entity beans:

  • Metadata annotations for O-R Mapping
  • Inheritance and polymorphism support
  • Simplified EntityManager API for CRUD operations for entity beans.
  • Enhancements in Query Capabilities

Metadata for O-R Mapping

The metadata for O/R mapping annotations allows users to “decorate” their EJB 3.0 entity bean classes with O/R mapping metadata. This metadata is then used to define the persistence and retrieval of their entity beans. On other words, you no longer have to define the O-R mapping in a vendor-specific descriptor.

The example above uses the @Table and @Column annotations to specify the underlying database table and column names for the entity beans. You can also use the mapping annotations to define the relationship between entities. For example:

                         

@ManyToOne(cascade=PERSIST, fetch=LAZY) 
@JoinColumn(name="MANAGER_ID", referencedColumnName="EMP_ID") 
public Employee getManager() { 
  return manager; 
} 
                      

See How To Mapping Annotations for a list of mapping annotations available for your use.

Inheritance

Inheritance is very useful in many scenarios. The two types of inheritance that are commonly used and supported by Oracle Application Server EJB 3.0 Preview are:

  • Single Table per class hierarchy
  • Joined Sub Class strategy

The inheritance is expressed using annotations. Here is an example code that uses Joined Sub Class strategy:

                         

@Entity
@Table(name="EJB_PROJECT")
@Inheritance(strategy=JOINED, discriminatorValue="P")
@DiscriminatorColumn(name="PROJ_TYPE")
public class Project implements Serializable {...}

@Entity
@Table(name="EJB_LPROJECT")
@Inheritance(discriminatorValue="L")
public class LargeProject extends Project {
...
}

@Entity
@Table(name="EJB_PROJECT")
@Inheritance(discriminatorValue="S")
public class SmallProject extends Project 
{
...
}
                      

Simplify API for CRUD Operation for Entity Beans

The javax.persistence.EntityManager API is used for creating, finding, updating and deleting entity bean instances. You no longer have to write complex code for looking up Entity bean instances and manipulating them. You can inject an instance of EntityManager in a session bean and use persist or find method on EntityManager instance to create or query entity bean objects, as in the following code:

                         

@Inject 
   private EntityManager em;
   private Employee emp;

    public Employee findEmployeeByEmpNo(int empNo) 
    {
        return ((Employee) em.find("Employee",empNo));
    }

   public void addEmployee(int empNo, String eName, double sal)
   {
      if (emp == null) emp = new Employee();
      emp.setEmpNo(empNo);
      .......
      em.persist(emp);
   }

}
                      

Query Enhancements

Simplifying Client View for EJBs

Using EJB is very complex even if EJBs are collocated in the same application. If you want to use an EJB 2.x from another EJB, for example, you have to define the ejb-ref or ejb-local-ref in the deployment descriptor, look up the EJB, create an instance, and then invoke a method. In contrast, with EJB 3.0, you can simply define the dependency on the bean using annotation and invoke the method as follows:

                         

 @EJB AdminService bean;

    public void privilegedTask() {
        bean.adminTask();
    }

                      

You can use dependency injection to lookup any type of environment and resource references such as DataSource, JMS, Web Service and so on.

Testability Usability Outside Container

For developers relying on the EJB 2.1 spec, testing is a nightmare as well. An EJB container is required to develop and test the EJBs and you have to be familiar with the final deployment platform to perform testing.

Thankfully, EJB 3.0 promises to let you test EJB outside of the container. The Entity Test Harness provided with Oracle Application Server EJB 3.0 Preview makes testing EJB 3.0 a reality.

Conclusion

EJB 3.0 looks very promising for enterprise Java developers. The proposals outlined in the EJB 3.0 specification will help remove the complexities for everyone of us. Oracle Application Server EJB 3.0 Preview has a full implementation of EJB 3.0 Early Release Draft2 specification and you can start building your EJB 3.0 application right now!

References and further reading

Author Bio

Debu Panda is a principal product manager of Oracle Application Server development team, where he focuses his efforts on the EJB container and Transaction Manager. He has more than 13 years of experience in the IT industry and has published articles in several magazines and has presented at many technology conferences. His J2EE-focused weblog can be found at http://radio.weblogs.com/0135826/.