Long before the EJB 3 specification was written, some developers disillusioned with EJB started to look for alternative frameworks. POJOs are an especially compelling alternative to EJBs. A POJO is simply a Java object that does not implement any special interfaces such as those defined by the EJB framework. The name was coined by Fowler, Rebbecca Parsons, and Josh MacKenzie [Fowler POJO] to give regular Java objects an exciting-sounding name. Later in this section you will see how this simple idea has some surprisingly important benefits.
However, POJOs by themselves are insufficient. In an enterprise application you need services such as transaction management, security, and persistence, which were previously provided by the EJB container. The solution is to use the increasingly popular so-called “lightweight” frameworks that replace some “heavyweight” parts of the J2EE stack. They do not completely replace the J2EE stack but can be used in combination with some parts of it to provide important enterprise services.
The four lightweight frameworks that I describe in this book are Hibernate, JDO, iBATIS, and Spring. Except for JDO, which is a specification, they are open source projects, which have helped drive the adoption of POJOs and lightweight frameworks by the community. Hibernate and JDO are persistence frameworks, which map POJOs to a relational database. They are layered on top of JDBC and significantly increase developer productivity. iBATIS is also layered on top of JDBC, but it maps POJOs to SQL statements and is a very convenient way to execute SQL statements. The Spring framework has a wide range of features that make it easier to use than EJB, including the equivalent of container-managed transactions for POJOs.
An important feature of these technologies is that they are nonintrusive. Unlike EJBs, they provide transactions and persistence without requiring the application classes to implement any special interfaces. Even when your application’s classes are transactional or persistent, they are still POJOs, which means that you continue to experience the benefits of POJOs that I describe in this article.
Some excellent books are available that describe these frameworks in depth: Hibernate in Action [Bauer 2005], Spring in Action [Walls 2005], iBATIS in Action [Begin, forthcoming], and Java Data Objects [Russell 2003]. You do not need to read these books to understand and benefit from this book. But to apply what you learn here you do need to read them to learn the details.
In this section I will provide an overview of how to use POJOs and lightweight frameworks to redesign the money transfer service and make it easier to develop, test, and maintain. This new design is object-oriented POJO-based instead of a procedural EJB-based. It accesses the database using a persistence framework that is layered on top of JDBC instead of using JDBC directly. The business logic is encapsulated by a POJO façade instead of a session bean, and transactions are managed by the Spring framework instead of the EJB container. The business logic returns real business objects to the presentation tier instead of DTOs. The application is assembled by passing a component’s dependencies as setter or constructor arguments instead of the component using Java Naming and Directory Interface (JNDI) lookups. Because the design is object-oriented and uses these lightweight technologies, it is much more developer-friendly than the EJB version we saw earlier.
Table 1.1 summarizes the differences between the two designs.
Table 1.1 Comparing classic EJB and POJO approaches
|Classic EJB approach
|Procedural-style business logic
|JDBC/SQL or Entity beans
|Returning data to the presentation tier
|EJB container-managed transactions
|Explicit JNDI lookups
Don’t worry if you are not familiar with all of these terms. In this section, I’ll examine each difference and explain and justify the POJO approach. You will see how to develop business logic using the POJO approach. I use the money transfer application from section 1.1.2 as an example.
Using an object-oriented design
Rather than structuring the money transfer example around methods such as transfer() and its helper methods, the code should be structured around an object model, which is a collection of classes that typically corresponds to realworld concepts. For example, in the money transfer application, the object model consists of classes such as Account, OverdraftPolicy, and BankingTransaction. In addition, there is a TransferService that coordinates the transfer of money from one account to another. Figure 1.1 shows the design.
Figure 1.1 An object model for the money transfer application
An Account maintains its balance and has an OverdraftPolicy, which determines what happens when the account is about to become overdrawn. OverdraftPolicy is an example of a Strategy pattern [Gang of Four] and there are two implementations of OverdraftPolicy: one for each type of real-world policy. Better yet, an OverdraftPolicy could encapsulate a rules engine and thereby enable the business rules for overdrafts to be changed dynamically. TransferTransaction, which is a subclass of BankingTransaction, records the transfer of money between two accounts.
Using an object-oriented design has a number of benefits. First, the design is easier to understand and maintain. Instead of consisting of one big class that does everything, it consists of a number of small classes that each have a small number of responsibilities. In addition, classes such as Account, BankingTransaction, and OverdraftPolicy closely mirror the real world, which makes their role in the design easier to understand.
Second, our object-oriented design is easier to test: each class can and should be tested independently. For example, we could write unit tests for Account and for each implementations of OverdraftPolicy. In comparison, an EJB can only be tested by calling its public methods, for example, transfer(), which is a lot more difficult. You can only test the complex functionality exposed by the public methods rather than test the simpler pieces of the design.
Finally, the object-oriented design in figure 1.2 is easier to extend because it can use well-known design patterns, such as the Strategy pattern and the Template Method pattern [Gang of Four]. Adding a new type of overdraft policy simply requires defining a new subclass of OverdraftPolicy. By contrast, extending an EJB-style procedural design usually requires changing the core code, and rewriting or chaining procedure calls together.
As you can see, our object-oriented design has some important benefits. But it is essential to know when it is not a good choice.
Once you break free of the constraints imposed by the EJB 2 programming model, implementing the object model shown in figure 1.2 is easy. Java provides all of the necessary features, including fine-grained objects, relationships, inheritance, and recursion. It is straightforward to implement expressive object models like this one using POJOs and thus benefit from improved maintainability and testability. Java is an object-oriented language, so it is foolish not to use its capabilities.
As a bonus, POJOs have these other important benefits:
- Easier development—There is less cognitive load because rather than being forced to think about everything—business logic, persistence, transactions etc.—at once you can instead focus on one thing at a time. You can first design and implement the business logic and then, once that is working, you can deal with persistence and transactions.
- Faster development—You can develop and test your business logic outside of the application server and without a database. You do not have to package your code and deploy it in the application. Also, you do not 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 can run in a few seconds and development can happen at the speed of thought—or at least as fast as you can type!
- Improved portability—You are not tied to a particular implementation technology. The cost of switching to the next generation of Java technology is minimized because you have to rewrite only a small amount of code, if any.
I was genuinely surprised by how POJOs changed how I went about development because I’d become so accustomed to the cumbersome EJB approach. As with the TiVo box I described earlier, I had to use them before I appreciated their true value. But now I couldn’t imagine reverting to the old way of working. Of course, you still need to handle persistence and transactions, which is where lightweight frameworks come in.
When the time comes to persist the POJOs that implement the business logic, there are some powerful object/relational mapping frameworks to choose from. The main ones are JDO, which is a standard from Sun, and Hibernate, which is an extremely popular open source framework. In addition, the specification for EJB 3 entity beans appears to be potentially quite powerful.
Transparent persistence with JDO and Hibernate
JDO and Hibernate provide transparent persistence, which means that the classes are unaware that they are persistent. The application just needs to call the persistence framework APIs to save, query, and delete persistent objects. The persistence framework automatically generates the SQL statements that access the database using an object/relational mapping, which is defined by XML documents or Java 5 annotations. The object/relational mapping specifies how classes map to tables, fields map to columns, and relationships map to either foreign keys or join tables. JDO and Hibernate can also run outside of the application server, which means that you can test your persistent business logic without deploying it in a server. You can, for example, simply run tests from within your integrated development environment (IDE).
Encapsulating the calls to the persistence framework
Even though Hibernate and JDO provide transparent persistence, some parts of an application must call the JDO and Hibernate APIs to save, query, and delete persistent objects. For example, TransferService must call the persistence framework to retrieve the accounts and create a BankingTransaction. One approach is for TransferService to call the persistence framework APIs directly. Unfortunately, this would couple TransferService directly to the persistence framework and the database, which makes development and testing more difficult.
A better approach is to encapsulate the Hibernate or JDO code behind an interface, as shown in figure 1.2. The persistence framework, which in this example is Hibernate, is encapsulated by the repository classes. Each repository consists of an interface and a Hibernate implementation class and is responsible for one type of object. The JDO implementation would be similar.
Figure 1.2 Using repositories to encapsulate the persistence framework hides the persistence details from the rest of the application.
In this example, repositories call the Hibernate APIs to access the database. AccountRepository finds accounts and BankingTransactionRepository creates BankingTransactions. The TransferService is written in terms of the AccountRepository and BankingTransactionRepository interfaces, which decouples it from the persistence framework and the database. By the intelligent use of interfaces, you can avoid coupling your domain logic to a particular persistence framework. This will enable you to test the domain model without the database, which simplifies and accelerates testing. It also enables you to use a different persistence framework if your needs change. For example, changing this application from Hibernate to JDO or even EJB 3 is simply a matter of changing the concrete classes that access the persistence framework. It’s a generally accepted observation that loosely coupled applications are easier to maintain and test.
Part two of this series offers information on how to
- Eliminate DTOs
- Return domain objects to the presentation tier
- Make POJOs transactional
- Manage these transactions with Spring
About the Author
Chris Richardson is a developer and architect with over 20 years of experience. His consulting company specializes in jumpstarting projects and mentoring teams. Chris has been a technical leader at Insignia, BEA, and elsewhere. He has a computer science degree from the University of Cambridge in England and lives in Oakland, CA.
About the Book
This material reprinted with permission and is based on material from Chapter 1 of POJOs in Action.
|POJOs in Action
By Chris Richardson
Published: January, 2006, Paperback: 592 pages
Published by Manning Publications
Retail price: $44.95