The EJB Advocate: Is EJB 2.x dead yet?

The EJB Advocate responds to a reader who declares that EJB 3.0 makes EJB 2.0 obsolete, and explores some of the new features of the EJB 3 specification, including the Java™ Persistence API (JPA). This exchange shows that while the benefits of these new specifications are good, they require you to make some simplifying assumptions that may not work for everyone. Since nearly all of these benefits can be provided as implementations of the EJB 2.x specification with the proper tooling, it is likely that EJB 2.x will be around for a while.

Share:

Geoff Hambrick (ghambric@us.ibm.com), Distinguished Engineer, IBM

Geoff HambrickGeoff Hambrick is a lead consultant with the IBM Software Services for WebSphere Enablement Team and lives in Round Rock, Texas (near to Austin). The Enablement Team generally helps support the pre-sales process through deep technical briefings and short term Proof of Concept engagements. Geoff was appointed an IBM Distinguished Engineer in March of 2004 for his work in creating and disseminating best practices for developing J2EE applications hosted on IBM WebSphere Application Server.



22 February 2006

Also available in Russian

From the IBM WebSphere Developer Technical Journal.

In each column, The EJB Advocate presents the gist of a typical back-and-forth dialogue exchange with actual customers and developers in the course of recommending a solution to an interesting design issue. Any identifying details have been obscured, and no "innovative" or proprietary architectures are presented. For more information, see Introducing the EJB Advocate.

Theory: Out with the old, in with the new

Hey EJB Advocate,

It's time to wake up and smell the coffee! EJB 2.x is dead! Long live EJB 3! Just look how much simpler life will get when creating a persistent object like a customer from one of your previous articles:

@Entity
@Table(name="CUSTOMER")
public class Customer implements Serializable {
	
	private int id;
	private String name;
	private Order openOrder;
	
public Customer () {
super();
}
	
	@Id
	@Column(name="CUST_ID")
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	
	@Column(name="NAME")
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@OneToOne(cascade=CascadeType.ALL , fetch=FetchType.EAGER )
	@JoinColumn(name="OPEN_ORDER_ID",referencedColumnName="ORDER_ID") 
	public Order getOpenOrder() {
		return openOrder;
	}
	public void setOpenOrder(Order openOrder) {
		this.openOrder = openOrder;
	}

}

I only need to create a simple POJO and annotate it. I don't have to inherit from anything. No separate home, interface, or deployment descriptor is required. And I don't have to perform a vendor-specific mapping step!

The code in a client program using EJB 3 is even simpler. Let's say I want to get the open order associated with the customer whose key is an integer called customerId:

@PersistenceContext (unitName="db2")
EntityManager em;
try {
	Customer c = (Customer)em.find(
		Customer.class, new Integer(customerId)
	);
	Order o = c.getOpenOrder();
	return o;
}
catch (EntityNotFoundException e) {
	throw new CustomerDoesNotExist(customerId);
}

Because the one EntityManager instance serves as the "home" to all entities, there is no JNDI lookup required. It doesn't get any simpler than that.

So tell me. Why go back to hamburger after eating steak?

Signed,
Never Going Back


Practice: Not so fast, there are tradeoffs to consider

Dear Never Going Back,

Because your note was a bit cheeky, I will (with tongue in cheek) take the opportunity to point out that the entity EJB component you are talking about is actually part of the Java Persistence API (JPA) which is a separate but related specification spun off of JSR 220. So, it is more correct to say something like "using JPA is simpler".

But seriously, I am glad you found a standard approach to persistence that you can live with. Too many folks I talk to end up inventing their own approach to persistence. I suppose that the "back" in your signing "Never Going Back" implies that you weren't one of these folks.

That said (and at the risk of making you unhappy again), the EJB Advocate is going to very carefully parse the advantages you point out so that you can truly weigh the benefits of JPA versus CMP entity components:

  1. JPA entity components are not POJOs.

    You first mentioned that you simply create a POJO and annotate it (with @entity among other things) to create a JPA style entity. That is true. But strictly speaking, most do not consider a persistence mechanism to be based on POJOs unless it can be used with an existing -- unmodified -- simple Java class.

    You might also want to think back to the EJB 1.x days when entity components were more like POJOs. The instance variables were declared as part of the bean implementation, which was a concrete class. You "annotated" the class by declaring it an entity EJB and implemented the lifecycle methods like ejbLoad() and ejb Store() (or left them up to the deployment tools). One reason that this approach was abandoned is because it made loading the CMP fields an all or nothing affair. The EJB 2.x approach enables the flexibility to do performance enhancing tricks like map the get<Property>() methods onto a database cursor or stream implementation, reducing the number of transformations. JPA allows for "lazily" loading the properties through annotation, but as we will see in a later point, this approach creates its own problems when coupled with thinking that the entity is a POJO.

  2. Neither JPA nor EJB 2.x requires that you subclass (extend) any particular class.

    You then mentioned that you need not "inherit" from anything when using JPA, implying that EJB 2.x entities do. This implication is not true. Consider a typical EJB 2.x entity component class declaration:

    public abstract class CustomerBean implements EntityBean ...

    A class (whether abstract or concrete) that implements an interface does not really inherit anything from the interface it implements. Implementing an interface is simply a marker that the class can play a given role in the application -- exactly like the @entity annotation is intended to do.

    This distinction is important because Java only supports single inheritance with respect to implementation. You may only extend a single class and inherit its method implementations. You can implement as many interfaces as you want.

    And because an EJB 2.x entity is an abstract class, you need not implement any of the various EJB lifecycle methods associated with the EntityBean interface like ejbLoad() and ejbStore(). These implementations can be deferred to the deployment tool provided by the vendor.

  3. JPA entity components do not support multiple views.

    Next, you pointed out that you need not create an interface or home with a JPA entity. True. But this simplicity comes with a tradeoff: you directly access the implementation class. The limitation is that you only get a single view of the component. Java interfaces are powerful in that you can provide views of an implementation component that are customized to the needs of a client. EJB 2.x entity components maintain the concept of separating the implementation from the interfaces it supports. For example, you can provide both a remote and a local view of an entity.

    Why would you want to provide a remote interface to an entity EJB component when a well known best practice is to use a facade? In a previous EJB Advocate article, we discussed how to exploit custom home methods on entity components to serve as a built in facade. Since a facade is often used remotely, a remote home interface could be provided that includes one or more custom methods like so:

    public interface CustomerHome implements EJBHome {
    	CustomerData ejbHomeGetOpenOrderForCustomer(int customerId) ...
    }

    Notice how this remote interface does not have any create() or find() methods. This deliberate omission ensures that an instance of the Customer entity can never be accessed remotely. The local interface and home to the same bean implementation would expose the create and find methods along with the appropriate get and set methods (that possibly represent CMRs as described in yet another EJB Advocate article).

    And, that said, most vendors of EJB-related tooling, like IBM Rational Application Developer for WebSphere software, generate the homes and interfaces in one step with a Wizard tool. Some even make it possible to start with the bean implementation, like a POJO, and promote methods to the interface and home as desired.

  4. JPA entity components mix implementation details into your POJOs.

    Another "advantage" you called out about JPA has to do with the ability to skip creating a separate deployment descriptor and skip a vendor-specific mapping step. That is all well and good -- especially the part about standard mappings to relational data stores -- but there is a tradeoff. You imbed the implementation details in the code, which makes the object even less like the simple POJO that you seemed to crave.

    One of the best features of EJB 2.x entity components is that the deployer could modify the details of how a given business object was made persistent completely independently of the bean provider. There is no reason that vendors cannot adopt a similar standard set of mapping annotations as part of an EJB 2.x style deployment descriptor to simplify the mapping step.

  5. JPA entity components are still best used behind a facade.

    Finally, you rightly pointed out that there is only one EntityManager implementation, which eliminates the need to do a JNDI lookup, and makes using a JPA entity component extremely easy. However, you failed to note that if you don't use the JPA entity within a transactional context, you need to do an explicit save to the EntityManager to persist any changes. Another aspect of JPA you failed to mention is that if an entity is declared to be "lazily" loaded in the annotations and is subsequently detached from the context (that is, the transaction ends), then the fields untouched are undefined.

    Having to explicitly manage the transactional context would add complexity to the JPA programming model. So it is still a best practice to use a session facade (whether a new EJB 3 style or an old EJB 2.x style). If you choose to return the POJO from the facade, you will either need to set the loading to "eager" or to touch all the fields in the JPA entity. With EJB 2.x custom home methods, a session is not absolutely required.

As you can see, most of the benefits of EJB 3 and JPA that you mention involve simplifying assumptions that may not work for all situations. You have to decide for yourself whether you can live with those assumptions. In cases where you can, I hope you see that almost all of them can be applied to the EJB 2.x specification through deployment tooling. Finally, even the JPA specification mentions that EJB 2.x is still expected to be used after EJB 3 and JPA are finalized.

Therefore (with apologies to Mark Twain), the EJB Advocate believes that the rumors of the demise of EJB 2.x have been greatly exaggerated.

OK then,
Your EJB Advocate


Conclusion

This exchange explored some fundamental questions about simplicity. For example, is it better to have a complex system that enables all the flexibility you need? Or is it better to have a simple system that makes it easy to handle the average case? In the musings above, the EJB Advocate wondered: why not provide for both by enabling flexibility but having a default case that makes things simple?

For those that prefer an object oriented approach to application development, EJB 2.x may still be the better approach, since it exploits all the features of Java that make it such a powerful language, especially the separation of interface from implementation.

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere, Java technology
ArticleID=104221
ArticleTitle=The EJB Advocate: Is EJB 2.x dead yet?
publish-date=02222006