EJB 3.0 in a nutshell

An overview and critical analysis of the latest EJB specification

Despite several positives, the complexity of the Enterprise JavaBeans architecture is hindering the adoption of J2EE. The EJB architecture is probably the only J2EE component that has failed so miserably in delivering J2EE's promise of increased developer productivity thorough ease of development. EJB 3.0 makes another attempt at delivering that promise by reducing EJB's complexity for developers. EJB 3.0 decreases the number of programming artifacts for developers to provide, eliminates or minimizes callback methods required to be implemented, and reduces the complexity of the entity bean programming model and O/R mapping model.

In this article, I first cover the most significant changes in EJB 3.0. It's important to have the basics in place before diving into the EJB 3.0 pool. Next, I give a high-level view of the EJB 3.0 draft and then get into specifics of the proposed specification, paying attention to all changes one-by-one: impact on types of enterprise beans, O/R mapping model, entity-relationship model, EJB QL (EJB Query Language), etc.

Background

The two most significant changes in the proposed EJB 3.0 specification are the use of the program annotation facility introduced in Java 5 and the new O/R mapping model based on Hibernate.

Metadata facility in Java 5

Java 5 (previously called J2SE 1.5, or Tiger) has introduced a new program annotation facility to the language. With this facility, you can define custom annotations and then annotate fields, methods, classes, etc., with these annotations. Annotations do not directly affect program semantics, but tools (compile time or runtime) can inspect these annotations to generate additional constructs (like a deployment descriptor) or enforce desired runtime behavior (like an EJB component's stateful nature). Annotations can be inspected through source parsing (e.g., compilers or IDE tools) or by using the additional reflection APIs added in Java 5. Annotations can be defined to be available only at the source code level, at the compiled class level, or at runtime. All annotations proposed in the EJB 3.0 early draft have a RetentionPolicy of RUNTIME. This increases the class's memory footprint marginally, but makes the life of container provider and tool provider much easier.

Refer to Resources for further reading on this topic.

Hibernate

Hibernate is a popular, open source O/R mapping framework for Java environments, meant to shield developers from most common data-persistence-related programming tasks. It also has a specific Hibernate Query Language (HQL), imprints of which can be seen in the new EJB QL. Hibernate offers facilities for data retrieval and update, connection pooling, transaction management, declarative entity relationship management, and declarative and programmatic queries.

Bird's eye view

The changes in the proposed EJB 3.0 specification can be divided into two categories:

  • An annotation-based EJB programming model, in addition to the EJB 2.1 model of defining an application's behavior through deployment descriptors and several interfaces.
  • The new persistence model for entity beans. EJB QL has also changed significantly.

There are also several side effects to these proposals, like a new client-programming model, use of business interfaces, and an entity bean life cycle. Please note that the EJB 2.1 programming model (with deployment descriptors and home/remote interfaces) is still valid. The new simplified model does not entirely replace the EJB 2.1 model.

EJB annotations

One of the expert group's important goals is to reduce the number of artifacts a bean provider must provide, and the group has done a pretty neat job in reaching that goal. In the EJB 3.0 world, all kinds of enterprise beans are just plain old Java objects (POJO) with appropriate annotations. Annotations can be used to define the bean's business interface, O/R mapping information, resource references, and just about anything else that was defined through deployment descriptors or interfaces in EJB 2.1. Deployment descriptors are no longer required; the home interface is gone, and you don't necessarily have to implement a business interface (the container can generate it for you).

For example, you declare a stateless session bean by using the @Stateless annotation on the Java class. For stateful beans, the @Remove annotation is marked on a particular method to indicate that the bean instance should be removed after a call to the marked method completes.

To reduce the amount of information you must specify for a component, the expert group has adopted a configuration-by-exception approach, meaning you provide intuitive defaults for all annotations so that most of the common information can be inferred.

The new persistence model

The new entity beans are also just POJOs with a few annotations and are not persistent entities by birth. An entity instance becomes persistent once it is associated with an EntityManager and becomes part of a persistence context. A persistence context is loosely synonymous with a transaction context; in strict words, it implicitly coexists with a transaction's scope.

The entity relationships are also defined through annotations. In addition, O/R mapping is also done through annotations, and support for several database-specific operations is provided. With EJB 2.1, developers used their own design patterns or employed nonportable techniques (for example, auto key generation strategies).

Digging deep

It's now time to get into the specifics of proposals made in the EJB 3.0 early draft. Let's start with all four types of enterprise beans and then move on to the proposals generic to the whole of the EJB programming model.

Stateless session beans:

A stateless session bean (SLSB), written the EJB 3.0 way, is just a plain Java file with a class-level annotation of @Stateless. The bean class can implement the javax.ejb.SessionBean interface, but is not required to (and typically will not).

An SLSB doesn't have a home interface anymore—in fact, no EJB type requires it. The bean class may or may not implement a business interface. If it does not implement any business interfaces, a business interface will be generated using all the public methods. If only certain methods should be exposed in the business interface, all of those methods can be marked with the @BusinessMethod annotation. By default, all generated interfaces are local, but the @Remote annotation can be used to indicate that a remote interface should be generated.

The following few lines of code are enough to define a HelloWorld bean. With EJB 2.1, the same bean would have required at least two interfaces, one implementation class with several empty method implementations, and a deployment descriptor.

import javax.ejb.*;
/**
 * A stateless session bean requesting that a remote business
 * interface be generated for it.
 */
@Stateless
@Remote
public class HelloWorldBean {
   public String sayHello() {
      return "Hello World!!!";
   }
}

Refer to Resources for the complete source code that accompanies this article.

Stateful session beans

The story with stateful session beans (SFSB) is pretty much the same for SLSB, except for a couple of SFSB-specific points:

  • An SFSB should have a way of initializing itself (provided through the ejbCreate() method in EJB 2.1 and earlier). The EJB 3.0 specification suggests that such initialization methods be provided as custom methods and exposed through the bean's business interface. The onus now lies with the client to call appropriate initialization methods before using the bean. The expert group is still debating the need for providing an annotation that marks a particular method for initialization.
  • The bean provider may mark any SFSB method with the @Remove annotation to indicate that the bean instance must be removed after the annotated method is called. Again, the expert group is still discussing whether a facility is necessary for indicating that the bean must not be removed if the method doesn't complete normally.

Here is my opinion on the two open issues:

  • Should an annotation for the initialization method exist? My vote is yes—with the assumption that the container will ensure that at least one of the initialization methods is called before any other business method is called. This not only guards against accidental programming mistakes, but also makes the container more confident about reusing SFSB instances. For clarity, let me mention here that no designated initialization methods (like ejbCreate) are under consideration; the expert group is only considering having an annotation mark a method as an initialization method.
  • Should it be configurable that abnormal termination of the @Remove method doesn't remove the bean instance? Again, my vote is yes. It will only give better control to the bean provider and client programmers. Only one question remains: what happens to those beans marked to be not removed on an unsuccessful call to the remove method and a particular instance's remove method never completes successfully? There is no way to remove those instances programmatically, but they will be removed on session timeout.

Refer to the source code for an example SFSB.

Message-driven beans

Message-driven beans (MDBs) are the only kind of bean that must implement a business interface. This interface's type indicates the type of messaging system that the bean supports. For JMS (Java Message Service)-based MDBs, this interface is javax.jms.MessageListener. Note that the MDB business interface is not truly a business interface, it is just a messaging interface.

Entity beans

Entity beans are marked with the @Entity annotation, and all properties/fields in the entity bean class not marked with the @Transient annotation are considered persistent. Entity bean persistent fields are exposed through JavaBean-style properties or just as public/protected Java class fields.

Entity beans can use helper classes for representing entity bean state, but instances of these classes don't have a persistent identity. Instead, their existence is tied strongly to the owning entity bean instance; also these objects are not shareable across entities.

Refer to the source code for some example entity beans.

Entity relationships

EJB 3.0 supports both unidirectional and bidirectional relationships between entity beans, which can be one-to-one, one-to-many, many-to-one, or many-to-many relationships. However, the two sides of a bidirectional relationship are distinguished as the owning side and the inverse side. The owning side is responsible for propagating relationship changes to the database. For many-to-many associations, the owning side must be explicitly specified. Actually it's the reverse side that is specified by the isInverse=true annotation member on the reverse side's ManyToMany annotation; from that, the owning side is deduced. Now, didn't the expert group say it was making EJB easier?

O/R mapping

The O/R mapping model has also significantly changed from the abstract-persistence-schema-based approach to a Hibernate-inspired one. Though the expert group is still discussing the model, and a clear picture will emerge only with the next draft, this draft features clear indications of the overall approach.

For one, the O/R mapping will be specified in the entity bean class itself by annotations. Also, the approach is to refer to concrete tables and columns instead of the abstract persistence schema. The O/R mapping model has intrinsic support for native SQL; that is, support at a deeper level, not just the ability to run native SQL queries. For example, the column definitions annotation (@Column) has a member columnDefinition that can be something like columnDefinition="BLOB NOT NULL".

Client programming model

An EJB client can acquire a reference to the bean's business interface using the injection mechanism (@Inject annotation). Using the newly introduced @javax.ejb.EJBContext.lookup() method is another approach. But the specification is not clear as to how a standalone Java client acquires reference to a bean instance since the standalone Java clients run in a J2EE client container and lack access to the @javax.ejb.EJBContext object. There is yet another mechanism—a newly introduced universal context object: @javax.ejb.Context(). But, again, the spec does not say how this object can be used in a client container.

EJB QL

Queries can be defined through the @NamedQuery annotation. Two members of this annotation are name and queryString. Once defined, this query can be accessed using the EntityManager.createNamedQuery(name) method. You can also create a regular JDBC-style (Java Database Connectivity) query by calling EntityManager.createQuery(ejbqlString) or a native query using EntityManager.createNativeQuery(nativeSqlString).

EJB QL queries can have both positional as well as named parameters. The javax.ejb.Query interface provides methods for setting these parameters, executing updates, listing results, etc.

Here is one example of how an EJB QL query can be created and executed:

.. ..
@NamedQuery(
name="findAllCustomersWithName",
queryString="SELECT c FROM Customer c WHERE c.name LIKE :custName"
)
.. ..
@Inject public EntityManager em;
customers = em.createNamedQuery("findAllCustomersWithName")
.setParameter("custName", "Smith")
.listResults();

The following lists some of the several enhancements made to the QL itself:

  • Support for bulk update and delete.
  • Explicit support for both inner and outer JOIN operations. A FETCH JOIN allows you to indicate that the related entities—e.g., Orders for a Customer—should also be fetched, though the SELECT clause only selects Customers.
  • More than one value can be returned from the SELECT clause. In fact, you can return a dependent class like this:

          SELECT new CustomerDetails(c.id, c.status, o.count)
          FROM Customer c JOIN c.orders o
          WHERE o.count > 100
    
  • Support for GROUP BY and HAVING.
  • Support for nested subqueries in the WHERE clause.

With the proposed specification, EJB QL is much closer to SQL than ever before. In fact, the specification supports native SQL directly, as noted above. This can prove disturbing for some programmers, and we'll come to that shortly.

Miscellaneous

Method permissions are specified through the @MethodPermissions or @Unchecked annotations; same goes for transaction attributes of methods that can be specified through the @TransactionAttribute annotation.

That still leaves the resource references and resource environment references. These can also be specified through annotations, but in slightly different way. Such context dependencies are handled with the injection facility. The container automatically initializes appropriately annotated instance variables of a bean with external references to environmental resources. For example, you can get a handle to a DataSource by doing the following:

@Resource(name="myDataSource") //Type is inferred from variable
public DataSource customerDB;

If the resource name is not specified, it defaults to the property name (customerDB, in this case). When all reference properties can be inferred, the @Inject annotation may be used instead:

@Inject public DataSource customerDB;

The container is responsible for initializing customerDB with the appropriate DataSource instance at runtime. The deployer must define these resources to the container at deployment time.

Yet more good news: the checked exceptions are gone. Though you can declare any arbitrary application exceptions, you do not have to throw and catch other exceptions like CreateException and FinderException . The container throws system-level exceptions wrapped in javax.ejb.EJBException or just throws IllegalArgumentException or IllegalStateException, where required by the spec.

EJB file-processing models

Before we wind up this section, let's quickly discuss how the container provider's EJB processing model could change. The spec is silent on this issue but I can see at least two models.

One way is to first process an EJB file to generate deployment artifacts (required interfaces and deployment descriptors) closer to the EJB 2.1 deployment model and deploy the EJB component similarly to how EJB 2.1 deploys it. Of course, such generated deployment descriptors and files can be nonstandard, but they might resemble the current ones. This approach, illustrated in the figure below, reduces rework for container providers and particularly reduces the burden of supporting both EJB 2.1 and EJB 3.0-style EJB components.

A potential EJB file-processing model. Click on thumbnail to view full-sized image.

Another possibility is a JSP-like (JavaServer Pages) drag-and-drop deployment model. You could drop an EJB file into a predesignated, implementation-defined directory and the container will pick it up, process it, deploy it, and make it available for use. This model can be built on top of the above approach, but will be a tremendous help in supporting iterative development. Considering that ease of development is one of the prime goals behind the EJB 3.0 specification, I sincerely hope the next draft would specify such a model (at least a nonnormative one).

What do you think?

EJB 3.0 is surely a job well done, and the expert group deserves all the praise for a wonderful effort towards making the life of an EJB programmer easier. With that said, life will be easier, but surely not easy, with more than 50 annotations already defined (several more expected in the next draft), each with its own set of rules for defaults and other behavioral specifications. Of course, I wasn't really expecting an "EJB 3.0 = EJB 2.1 for dummies" kind of equation. Still, I would like to express my humble opinion about a few issues:

  • For one, the specification has surely made iterative development easier with fewer program artifacts, intuitive defaults, and a simpler model for access to the runtime environment. I also like the fact that the home interface is gone, which means fewer artifacts to even visualize.
  • In earlier EJB specifications, entity beans used to be a view into the persistent store. It was theoretically (and probably only theoretically) possible to map an entity bean to any legacy EIS (enterprise information system) also. Doing so was accomplished with longer-term extensibility in mind and was meant to allow wider adoption of entity beans for business data modeling. Instead, the accompanying complexity only hurt the prospects of entity beans. As proposed in this draft, an entity bean is just a view into the database. Life is much simpler with no abstract persistent schemas and a simpler data-access model.
  • While I warmly welcome the above change, I'm not comfortable with the idea of having SQL snippets in EJB code (annotations). Some developers are totally against even the apparent "SQLness" of annotations (like @Table and @Column annotations). In my opinion, this "SQLness" is okay—after all, we are clear that we are talking about databases. But SQL snippets like columnDefinition="BLOB NOT NULL" make me really nervous because such an approach encourages a tight coupling between EJB code/annotations and SQL representation of the same.
  • Though support for native SQL queries appears tempting, embedding SQL in EJB code is a very, very bad idea. Of course there are ways to avoid hard-coding your SQLs, but those approaches would serve better as part of the specification, rather than individual developers' custom patterns.
  • I assume that use of annotations like @Table is only declarative in the bean class. The table name specified through the name member of the @Table annotation will probably have to be mapped to actual database tables at deployment time. The specification should be explicit on this issue and prescribe a consistent model.
  • The specification also needs to be more explicit about changes to the client-programming model, particularly standalone Java clients. All references to the client-programming model in the draft have implicitly assumed EJB clients. The draft also fails to touch on the issue of backward compatibility for client programs.
  • The Transient annotation should probably be renamed to avoid conflict if it is used in place of the transient keyword. In fact, on this issue, I believe we should be willing to deviate slightly from the configuration-by-exception approach and define an @Persistent annotation to explicitly mark all persistent fields. The @Persistent annotation could be just a marker annotation or it could have a few annotation members to possibly associate with O/R mapping annotations.

Relationship to other specifications

Some of the concurrently developing Java Specification Requests that might affect EJB 3.0 are JSR 175 (Metadata Facility for the Java Programming Language) and JSR 181 (Web Services Metadata for the Java Platform).

JSR 175 is mostly finalized and should not have much of an impact even if changes result; whereas, JSR 181 has two associations with EJB 3.0:

  • Web service interface: The EJB specification will adopt the mechanism laid out by JSR 181 that specifies that a bean implements a Web service and how the Web service is exposed to clients.
  • JSR 181 proposes different mechanisms for specifying security semantics. EJB 3.0's proposals are more in line with the mechanism in earlier EJB specifications (MethodPermissions), but JSR 181 proposes a slightly different approach (SecurityRoles and SecurityIdentity annotations). Similarly, the definition of the RunAs annotation also slightly differs. This issue is still open and will be decided at the J2EE level to maintain a consistent mechanism throughout.

Some other developing specifications targeted at J2EE 1.5 might have some association with EJB 3.0. But, with the exception of a few platform-level annotations for transactions and security discussed above, currently no other developing specs will have an impact on EJB 3.0.

Conclusion

We still have a long way to go before EJB programming becomes a pleasant experience—one that doesn't require exceptional expertise. But the expert group surely has made a good start at reducing complexity. O/R mapping proposals are in their early phases, and the expert group is still working on them. We just hope the model won't turn out to be as complex and excessively SQL-bound as it seems at this stage. Let's not just stop there (wishin 'n' hopin 'n' thinkin 'n' prayin): express your opinion by sending your comments to the expert group at ejb3-feedback@sun.com. The Java Community Process is not exactly a democracy, but your opinion counts.

The views in this article are the author's own and not related to his employer in any way. The author would like to thank Hemant Khandelwal for his help in reviewing this article.

The downloadable source code is a simplified version of illustrative examples provided in the EJB 3.0 early draft. Since no tools are available, the samples are not verified. Use them just as an illustrative sample of what EJB 3.0 beans will look like.

Anil Sharma is a senior engineer working for BEA Systems on the WebLogic Integration product. He has spent most of his career working on J2EE technologies, working for Oracle and Pramati Technologies in product development teams before joining BEA. In his spare time, he likes to listen to music and watch movies; he has also started getting involved with some open source initiatives.

Learn more about this topic

Join the discussion
Be the first to comment on this article. Our Commenting Policies