Close Window

Print Story

Cover Story: What Is POJO Programming?

The novel A Deepness in the Sky by Vernor Vinge is set in the distant future. The character Pham Nuwen is responsible for maintaining software whose components are thousands of years old. Today, however, it's difficult to imagine maintaining an Enterprise Java application for more than a few years. More often than not, the application is tightly coupled to infrastructure frameworks that evolve rapidly in ways that don't preserve backwards compatibility. Consequently, upgrading to a new and improved framework can be challenging and risky.

Fortunately, there's now a much better way to build Enterprise Java applications: Plain Old Java Objects (POJOs), which are classes that don't implement infrastructure framework-specific interfaces, and non-invasive frameworks such as Spring, Hibernate, JDO, and EJB 3, which provide services for POJOs.

Using POJOs future proofs your application's business logic by decoupling it from volatile, constantly evolving infrastructure frameworks. Upgrading to a new version or switching to a different framework becomes easier and less risky. POJOs also make testing easier, which simplifies and accelerates development. Your business logic will be clearer and simpler because it won't be tangled with the infrastructure code. And, as an added bonus, you can often deploy a POJO application using a simpler, Web container-only application server.

In this article, you'll learn about POJO programming. I'll begin by describing the concept of POJOs. You'll then get an overview of persisting POJOs with Hibernate and EJB 3 and making them transactional with EJB 3 and Spring. Of course, it's unlikely that the applications we're developing today will be used thousands of years from now but until their demise, using POJOs will make it easier to upgrade them to use newer frameworks.

What Is a POJO?
Even though it has tremendous benefits, the concept of a POJO is remarkably simple. A POJO is a Java object that doesn't implement any special interfaces such as those defined by the EJB 2 framework. Martin Fowler, Rebbecca Parsons, and Josh MacKenzie coined the name to give regular Java objects an exciting-sounding name that encouraged developers to use them (www.martinfowler.com/bliki/POJO.html).

To contrast the EJB and POJO approaches consider the following example. Imagine that you worked for a bank and needed to implement a service to transfer money from one bank account to another. If you were using EJB2, your code would most likely consist of a MoneyTransferService stateless session bean that coordinated the transfer of money between the accounts and an Account entity bean that accessed the account data. The problem with this design is that each EJB would be a mixture of business logic and EJB 2 infrastructure code. They would be intimately coupled to the EJB 2 framework. Furthermore, they would be difficult to test without deploying unless you jumped through the kinds of hoops described in TwoLevelDomain (www.theserverside.com/articles/article.tss?l=TwoLevelDomainModel).

By comparison, the POJO version (which is downloadable from www.pojosinaction.com) would look something like Listing 1. The MoneyTransferService and its implementation class define a transfer() method and the Account class maintains a balance and defines debit() and credit() methods. The AccountDAO is the interface for the Data Access Object (DAO) class whose implementation I'll describe later.

As you can see, these are regular Java classes. None of them implement special interfaces or call any framework classes. What's more, the MoneyTransferService doesn't instantiate the AccountDAO directly or look it up using an API such as JNDI. Instead, the AccountDAO is passed as a constructor parameter. This is an example of what is termed dependency injection, which is one of the key enablers for POJO development (www.martinfowler.com/articles/injection.html). In this example, dependency injection decouples the MoneyTransferService from the infrastructure framework. The MoneyTransferService only depends on the AccountDAO interface - not on the framework used to implement the AccountDAO or an API such as JNDI.

You could, of course, simplify the MoneyTransferService by dispensing with the AccountDAO and directly injecting, for example, a Spring HibernateTemplate or an EJB 3 EntityManager. However, I generally prefer to keep my framework-specific data access code separate from my business logic.

The Benefits of POJOs
Decoupling the application code from the infrastructure frameworks is one of the many benefits of using POJOs. They also simplify development because rather than being forced to think about everything - business logic, persistence, transactions, etc. - at once, you can focus instead on one thing at a time. You can design and implement the business logic and then, once that's working, you can deal with persistence and transactions.

POJOs also accelerate development. You can test your business logic outside of the application server and without a database. You don't have to package your code and deploy it in the application server. You also don't have to keep the database schema constantly in sync with the object model or spend time waiting for slow-running database tests to finish. Tests run in a few seconds and development can happen at the speed of thought - or at least as fast as you can type!

But by now you probably have questions such as what about transactions? Security? Persistence? Remoting? And how do you assemble an application with dependency injection? As you might have guessed, POJOs by themselves are insufficient. To use them in an enterprise application you have to use one or more frameworks.

Overview of Frameworks for POJOs
When developing an enterprise application, you need services such as transaction management, security, and persistence. You also need a way to assemble components together and access enterprise resources such as JDBC DataSources. One option is to use some very popular non-EJB frameworks such as Hibernate, JDO, and Spring. The Hibernate and JDO frameworks provide persistence for POJOs. The Spring framework provides services for POJOs such as transaction management and dependency injection. It also has support for POJO remoting and is the foundation of the Acegi Security framework (http://acegisecurity.sourceforge.net) that provides security for POJOs. One big of advantage of not using the EJB container is that you can sometimes deploy your POJO application in a simple (and sometimes cheaper) Web container-only server.

Another option is to use the emerging EJB 3 standard, which has adopted many POJO concepts and is a big improvement over EJB 2. In EJB 3, EJBs are very POJO-like in not implementing any special interfaces. Furthermore, EJB 3 entity beans are intended to be the standard persistence mechanism for Java and work both inside and outside the EJB container.

One important benefit of EJB 3, Spring, Hibernate, and JDO is that they are non-invasive. Unlike older technologies such as EJB2, they provide services such as transactions and persistence without requiring the application classes to implement any special interfaces. Moreover, only a small fraction of your code must call any APIs. Classes can be transactional or persistent while still being POJOs.

To use the services provided by these frameworks you must write metadata that configures the frameworks. The metadata comes in the form of either Java 5 annotations or XML configuration files. Later in this article, I'll provide examples of how you use this metadata to map POJOs to a relational database and make them transactions.

Now that you have had an overview of POJOs and their associated frameworks, let's look at dependency injection, persistence, and transaction management in more detail.

Injecting Dependencies into POJOs
Earlier we saw how the AccountDAO was passed as a constructor parameter to the MoneyTransferService. This kind of dependency injection is called constructor injection. Another kind of dependency injection is setter injection and consists of passing dependencies as setter parameters. The third kind of dependency injection is field injection and involves initializing fields directly. I prefer to use constructor injection because it ensures that an object is constructed with the required dependencies but setter and field injection are also useful.

Dependency injection has the following benefits:

There has to be some application start-up code that instantiates the components and wires them together. You could write the start-up code yourself. For example, you could write some code that creates an instance of a class that implements AccountDAO and then passes it to an instance of the MoneyTransferServiceImpl. However, in a typical application it's usually more convenient to let Spring or EJB 3 inject the dependencies for you.

Spring Dependency Injection
Dependency injection is one of the core features of the Spring framework. To use it, you must configure Spring's bean factory, which is a sophisticated factory that instantiates objects and wires them together using either constructor injection or setter injection. Here's an example of how to do that:

<bean name="moneyTransferService" class="... MoneyTransferServiceImpl">
    <constructor-arg ref="accountDAO"/>
</bean>

<bean name="accountDAO" class="... AccountDAOHibernateImpl">
...
</bean>

Each Spring bean definition includes a name, an implementation class, and one or more dependencies, which are supplied by either constructor or setter injection. When the presentation tier asks the bean factory to create a MoneyTransferService, first it will instantiate an AccountDAOHibernateImpl, which is the Hibernate implementation of the AccountDAO interface. The bean factory will then instantiate the MoneyTransferServiceImpl passing the AccountDAOHibernateImpl to its constructor.

Spring provides an extremely flexible dependency injection mechanism. It can inject aribitrary POJOs in POJOs. Spring can even, for example, do a JNDI lookup to get an object and inject it into a POJO.

EJB 3 Dependency Injection
In comparison, EJB 3 dependency injection is limited to injecting values from JNDI into either session beans or message-driven beans. You can configure field or setter injection using either XML or annotations. Listing 2 shows how you could inject an AccountDAO into a MoneyTransferServiceImpl using an annotation.

In this example, the @EJB annotation specifies that when the EJB 3 container instantiates a MoneyTransferServiceImpl it must initialize the accountDAO field with a reference to an AccountDAO. Behind the scenes, the EJB 3 container does a JNDI lookup of the AccountDAO, which is also implemented as a session bean. If the MoneyTransferServiceImpl called the EJB 3 persistence APIs directly then you'd simply inject the EJB 3 EntityManager directly.

Dependency injection is one of the cornerstones of POJO development. Another one is the ability to persist POJOs with an object/relational mapping (ORM) framework.

Persisting POJOs
POJOs often have to be persisted in a relational database. For example, the Money Transfer application must store Account objects in the ACCOUNT table. It could, of course, access the database using JDBC or iBATIS. Sometimes this is the right approach. But unless you have a really simple object model, it can be a lot of work to develop and maintain the Data Access Objects (DAOs) and the SQL needed to transfer objects to and from the database. It's usually a lot easier to use an ORM framework.

An Overview of ORM
When using an ORM framework you declaratively specify how your object model maps to the database schema. You specify how classes map to tables; fields map to columns, and relationships map to either foreign keys or join tables. The ORM framework then generates the SQL statements to create, find, update, and delete persistent objects. It also keeps track of which objects have changed and automatically writes them back to the database. As a result, you have to write a lot less code. Moreover, it's usually a lot easier to switch databases because the ORM framework is generating the SQL for you.

EJB 2 CMP provides a primitive form of ORM. However, it requires your classes to implement or extend EJB interfaces. In comparison, modern ORM frameworks such as Hibernate, JDO, and EJB 3 provide what's termed transparent persistence. Apart from perhaps having to add a field to store the primary key, the code for the objects shows no sign that they are persistent. The only classes that are dependent on the ORM framework are classes such as DAOs that create, find, and delete persistent objects. Let's look at an example.

Declarative Mapping
When using an ORM framework you define the mapping using either XML or Java 5 annotations. Table 1 shows how you map the Account class to the ACCOUNT table using EJB 3 annotations and a Hibernate 3 XML mapping document.

In each example, the Account class is mapped to the ACCOUNT table; the id field that stores the primary key is mapped to the ACCOUNT_ID column; and the balance field is mapped to the BALANCE column.

AccountDAOHibernateImpl
Once you've defined the mapping you can use the ORM framework's API for creating, finding, and deleting persistent objects. The APIs provided by each of the ORM frameworks are pretty similar. Here's an example of a DAO that uses a Spring HibernateTemplate, which is an ease-of-use wrapper around the Hibernate APIs:

public class AccountDAOHibernateImpl
   implements AccountDAO {
     private HibernateTemplate hibernateTemplate;
     public AccountDAOHibernateImpl(HibernateTemplatetemplate) {
     hibernateTemplate = template;
   }
     public Account findAccount(String accountId) {
     return (Account) hibernateTemplate.get(new Integer(accountId));
   }
...
}

The HibernateTemplate is passed to the AccountDAOHibernateImpl using constructor injection. The findAccount() method loads an account by calling HibernateTemplate.get(). When get() is called, Hibernate generates and executes a SELECT to load the corresponding row from the ACCOUNT table. If the Account object is then modified by the application, Hibernate will execute an UPDATE statement to save the changes in the database. An EJB 3 DAO would work the same way. It would call the EJB 3 EntityManager to create, find, and delete persistent objects.

But There Are Also Some Drawbacks and Limitations
When used appropriately ORM is an extremely powerful tool that can significantly increase development productivity while providing excellent performance. But like every tool, it has its limitations. For example, an ORM framework might not be a good choice in the following situations:

Don't be afraid to use SQL when you have to.

Making POJOs Transactional
Transactions are an essential part of the Enterprise Java application. Without them we risk corrupting data. Consider, for example, the MoneyTransferService shown earlier in Listing 2. It's vital that when the transfer() method executes in a transaction that you ensure that updates are made atomically. Otherwise, if the application crashes after debiting one account but before crediting the other account the money could disappear into the ether.

One of the nice features of EJB2 session beans is its support for container-managed transactions, which are a form of declarative transaction management. They simplify the application and make it more reliable by eliminating error-prone transaction management code. In a POJO application, the two main ways to implement declarative transaction management are to use either the Spring framework or EJB 3. Both frameworks use either Java 5 annotations or XML to specify the transactional attributes of a POJO.

Spring Transaction Management
The Spring bean factory does more than simply instantiate objects. It can also wrap the objects that it creates with interceptors (a k a proxies). These interceptors are how Spring provides a simple, yet effective Aspect-Oriented programming (AOP) implementation. AOP is the foundation of Spring transaction management. To make a POJO transactional you configure the bean factory to wrap it with TransactionInterceptor, which executes method calls within a transaction.

Spring provides a couple of ways to configure the bean factory to apply the TransactionInterceptor. One option is to use the @Transactional annotation on the interface, implementation class, or individual methods. For example:

@Transactional interface MoneyTransferService {...}

The @Transactional specifies that when the Spring bean factory instantiates the MoneyTransferServiceImpl that implements the interface, it must apply TransactionInterceptor.

Another option is to write XML bean definitions that explicitly apply the TransactionInterceptor to the POJO. Here's an example bean definition that uses the Spring BeanNameAutoProxyCreator to apply a TransactionInterceptor to the MoneyTransferService.

<bean id="transactionProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"
   <property name="beanNames">
    <list>
   <idref bean="moneyTransferService" />
    </list>
</property>
<property name="interceptorNames">
    <list>
     <idref bean="transactionInterceptor" />
    </list>
</property>
</bean>

The XML is more verbose than the annotation but has the advantage of leaving the source code unchanged. It also works with older JDKs that don't support annotations.

Spring doesn't implement transactions itself but is, instead, a wrapper around other transaction management APIs. Unlike EJB 3, it gives you the flexibility of using either JTA (as provided by an application server) or the transaction management APIs provided by ORM frameworks such as Hibernate and JDO.

EJB 3 Transaction Management
In EJB 3, declarative transaction management is, as you might expect, one of the built-in features of session and message-driven beans. You configure transaction management using either Java 5 annotations or a more traditional EJB deployment descriptor. This means, for example, that the MoneyTransferService EJB shown in Listing 2 will automatically be transactional.

Now that we've looked at how to make POJOs transactional and persistent let's examine the dangers of using annotated POJOs.

Beware of Annotated POJOs
The examples in this article use both XML and annotations to configure POJOs. However, the trend in POJO programming is away from XML configuration files and towards annotations. Annotations are certainly convenient because they're physically next to the program element (class, field, method) that they configure. The metadata is more concise and easier to maintain. There's certainly nothing wrong with using application-specific annotations. But, the problem with framework-specific annotations is that they couple your application to the framework in the same way that an API call does (www.aspectprogrammer.org/blogs/adrian/2004/08/ when_is_a_pojo.html).

For example, if you use Spring's @Transactional attribute then your classes won't compile without Spring. Similarly, if you use EJB 3 annotations then your classes will be coupled to the EJB 3 framework. These annotations won't stop you from testing your code with simple JUnit tests, but are classes that use them still POJOs?

Moreover, other annotations such as EJB 3's @EJB annotation, which injects an EJB, let you write code that's difficult to test without running it in the EJB container.

class SomeServiceImpl {
    @EJB private AccountDAO accountDAO;...
}

The @ EJB annotation tells the EJB container to "magically" initialize the private field on creation. Not a very POJO-like operation. Similarly, other frameworks' annotations couple your code to the database schema.

These kinds of annotations are definitely handy but using them will couple your application to the framework. That makes it difficult to support multiple frameworks simultaneously. Migrating to a later version or to a new framework can be difficult because you might have to change all of the annotations. This isn't quite as bad as rewriting the code but you still have to change the Java source and most importantly, you have to recompile. If you want to decouple your application from evolving infrastructure frameworks then you might want to consider using pure POJOs and XML metadata.

Summary
Developing with POJOs and non-invasive frameworks such as Spring, Hibernate, JDO, and EJB 3 provide many benefits. POJOs simplify and accelerate development. They make it easier to test classes in isolation without deploying them in an application server, a process that often slows down the edit-compile-debug cycle. And because POJOs are decoupled from the infrastructure frameworks that provide services such as transaction management and persistence you can focus on developing the business logic and address those concerns later.

POJOs also make it easier to upgrade your application to newer version of a framework or switch to a different framework entirely. They give your application increased immunity from the problems caused by rapidly evolving infrastructure frameworks. POJOs enable us to build Enterprise Java applications that last.

References

Acknowledgements
I would like to thank Chris Smith, Michael Yuan, Jennifer Shi, David Vydra, and Robert Benson for commenting on this article.

© 2008 SYS-CON Media Inc.