New features: simplifying EJB

There are three primary sources of complexities in EJB 2: the heavyweight programming model, direct use of the Java Naming Directory Interface (JNDI), and a verbose XML deployment descriptor. Three primary techniques in EJB 3 eliminate these sources of complexity: metadata annotations, minimal deployment descriptors, and dependency injection. In the following sections, we introduce all three of these major innovations that make developing EJB 3 as quick and easy as possible. Let’s begin by looking at how annotations and deployment descriptors work.

Replacing deployment descriptors with annotations

Service configuration using Java metadata annotations is easily the most important change in EJB 3. As you’ll see throughout the topic, annotations simplify the EJB programming model, remove the need for detailed deployment descriptors, and act as an effective delivery mechanism for dependency injection.

In the next few years, it’s likely that annotations will play a greater role in improving Java Standard Edition (SE) and Java Enterprise Edition (EE) usability by leaps and bounds. In case you aren’t familiar with the metadata annotation facility added in Java SE 5.0, let’s review it first.

Java metadata annotations: a brief primer

Annotations essentially allow us to "attach" additional information (officially called attributes) to a Java class, interface, method, or variable. The additional information conveyed by annotations can be used by a development environment like Eclipse, the Java compiler, a deployment tool, a persistence provider like Hibernate, or a runtime environment like the Java EE container. Another way to think about annotations is that they are "custom" Java modifiers (in addition to private, public, static, final, and so on) that can be used by anything handling Java source or byte code. This is how annotations look:


tmp24-14_thumb

The @Author symbol is the annotation.More interestingly, it adds this bit of extra information about the class without forcing us to implement an interface, extend a class, or add a member variable or method. Since an annotation is a special kind of interface, it must be imported from where it is defined. In our case, the @Author annotation is defined in the mypackage.Author.class file. This is all there is to making the compiler happy. The runtime environment decides how the @Author annotation should be used. For example, it could be used by the Manning website engine to display the author names for this topic.

Like many of the Java EE 5.0 innovations, annotations have humble beginnings. The @ character is a dead giveaway to the grandparent of annotations— JavaDoc tags. The next step in the evolution of the annotation from the lumbering caveman JavaDoc tag was the XDoclet tool. If you’ve done a significant amount of work with EJB 2, you are likely already familiar with XDoclet. XDoclet acted as a source code preprocessor that allowed to you to process custom Java-Doc tags and do whatever you needed to do with the tagged source code, such as generate PDF documentation, additional source code, or even EJB 2 deployment descriptors. XDoclet referred to this paradigm as attribute-oriented programming. In case you’re curious, you can find out more about XDoclet at http://xdoclet.source-forge.net/xdoclet/index.html.

The sleek new annotation facility essentially makes attribute-oriented programming a core part of the Java language. Although this is entirely possible, it is probably unlikely you’ll be creating your own annotations.

Note that, just like anything else, annotations and attribute-oriented programming have a few weaknesses. Specifically, it isn’t always a good idea to mix and match configuration with source code such as annotations. This means that you would have to change source code each time you made a configuration change to something like a database connection resource or deployment environment entry.

EJB 3 solves this problem by allowing you to override annotations with XML deployment descriptors where appropriate.

Know your deployment descriptor

A deployment descriptor is simply an XML file that contains application configuration information. Every deployment unit in Java EE can have a deployment descriptor that describes its contents and environment. Some typical examples of deployment units are the Enterprise Archive (EAR), Web Application Archive (WAR), and the EJB (ejb-jar) module. If you have ever used EJB 2, you know how verbose the XML (ejb-jar.xml) descriptor was. Most elements were required even if they were trivial. This added to the complexity of using EJB. For example, you could have had the following deployment descriptor for the HelloUserBean that we saw in topic 1:

tmp24-15_thumb

We’ll discuss deployment descriptors in greater detail when we talk about EJB packaging in topic 11. The good news is that EJB 3 makes deployment descriptors completely optional. You can now use metadata annotations instead of descriptor entries, thus making the development experience much simpler. Note that we’ll primarily use annotations throughout this topic. This is not because we think deployment descriptors are unimportant or outdated, but because concepts are more easily explained using annotations. As a matter of fact, although deployment descriptors involve dealing with often confusing and verbose XML, we think they can be an excellent mechanism for separating coding concerns from deployment and configuration concerns.

You can use deployment descriptor entries only for corner cases where you need them. (A corner case is a problem or situation that occurs only outside normal operating parameters.)

Mixing annotations and deployment descriptors

Annotations and descriptors are not mutually exclusive. In fact, in EJB 3 they’re designed for harmonious coexistence. Deployment descriptor entries override configuration values hard-coded into EJB components. As an example, we could override the @Author annotation we just introduced with the following imaginary deployment descriptor:

tmp24-16_thumb

This is an invaluable feature if you develop enterprise applications that can be deployed to a variety of environments. In the simplest case, the differing environments could be a test and a production server. In the most complex case, you could be selling shrink-wrapped enterprise applications deployed to an unknown customer environment. The most obvious way of mixing and matching annotation and XML metadata is to use XML for deployment environment-specific configurations while using annotations for everything else. If you really don’t like annotations, that’s fine too. You can avoid using them completely in favor of XML deployment descriptors. We’ll primarily focus on annotations rather than deployment descriptors in this topic simply because they are so much more intuitive to look at and explain.

Common metadata annotations

Obviously, EJB defines its own set of standard annotations. We’ll be discussing these annotations throughout this topic.

During the course of developing Java EE 5.0, it became apparent that the Java EE container as a whole could use some of the annotations geared toward EJB 3. In particular, these annotations are extremely useful in integrating EJB with the web/servlet tier. Some of these annotations were separated out of the EJB 3 spec and christened common metadata annotations. These annotations are a core part of what makes EJB 3 development, including dependency injection, easy. Table 2.1 lists some of the major common metadata annotations.

Table 2.1 Major metadata annotations introduced in Java EE. Although primarily geared toward EJB, these annotations apply to Java EE components such as servlets and JSF managed beans as well as application clients. Annotations defined in the javax.annotation.* package are defined by the Common Metadata Annotations API (JSR-250).

Annotations

Usage

Components That Can Use Them

tmp24-17

Dependency injection of resources such as Data-Source, JMS objects, etc.

EJB, web, application client

tmp24-18

Dependency injection of session beans

EJB, web, application client

tmp24-19

Dependency injection of web services

EJB, web, application client

tmp24-20

Dependency injection of container-managed EntityManager

EJB, web

tmp24-21

Dependency injection of EntityManagerFactory

EJB, web

tmp24-22

Lifecycle method

EJB, web

tmp24-23

Lifecycle method

EJB, web

tmp24-24

Security

EJB, web

tmp24-25

Security

EJB

tmp24-26

Security

EJB

tmp24-27

Security

EJB

tmp24-28

Security

EJB, web

As you can see, dependency injection is front and center of the common metadata annotations, including thetmp24-29_thumb

tmp24-30_thumbannotations. Just as metadata annotations take the ugliness of descriptors away from the developer’s view, dependency injection solves the complexities surrounding manual JNDI lookups. Let’s take a look at this concept next.

Introducing dependency injection

Almost every component uses another component or resource to implement functionality. The primary goal of dependency injection (DI) is to make component interdependencies as loosely coupled as possible. In real terms, this means that one component should call another component or resource only through an interface and that components and resources should be glued together using configuration instead of code. As a result, component implementations can easily be swapped out as necessary simply by reconfiguring the application.

If you’ve used JNDI extensively in EJB 2, you’ll appreciate how much this means. We won’t talk about JNDI very much here since in most cases you can get away without knowing anything about it.

In a sense, injection is lookup reversed. As you can see, in the manual JNDI lookup model, the bean explicitly retrieves the resources and components it needs. As a result, component and resource names are hard-coded in the bean. With DI, on the other hand, the container reads target bean configuration, figures out what beans and resources the target bean needs, and injects them into the bean at runtime. In the end, you write no lookup code and can easily change configuration to swap out beans and resources as needed.

When you're using JNDI, it's the responsibility of the client to do a lookup and obtain a reference to the object. In EJB 3, you may think dependency injection is the opposite of JNDI. It is the responsibility of the container to inject an object based on the dependency declaration.

Figure 2.1 When you’re using JNDI, it’s the responsibility of the client to do a lookup and obtain a reference to the object. In EJB 3, you may think dependency injection is the opposite of JNDI. It is the responsibility of the container to inject an object based on the dependency declaration.

In essence, DI allows you to declare component dependencies and lets the container deal with the complexities of service or resource instantiation, initialization, sequencing, and supplies the service or resource references to the clients as required. As we work our way through the examples in this topic, you’ll see several places where we use DI, including @ejb to inject EJBs in section 2.3, @Resource to inject JMS resources in section 2.4, and @PersistenceContext to inject container-managed EntityManager in section 2.5.

NOTE Lightweight application containers like the Spring Framework and Pico-Container popularized the idea of DI. To learn more about the roots of DI itself, visit www.martinfowler.com/articles/injection.html. This article, by Martin Fowler, faithfully examines the pros and cons of DI over JNDI-style manual lookups. Since the article was written before EJB 3 was conceived, you might find the discussion of EJB 2 cool as well!

Now that we’ve covered some of the most fundamental concepts of EJB 3, it is time to warm up to code. The problem we solve in this topic utilizes an essential element of this topic—ActionBazaar. ActionBazaar is an imaginary enterprise system around which we’ll weave most of the material in this topic. In a sense, this topic is a case study of developing the ActionBazaar application using EJB 3.

Let’s take a quick stroll around the bazaar to see what it is all about.

Next post:

Previous post: