What's New in EJB 3.0 Blog

Version 2



    Using Annotations Instead of
    Callback Methods and Listener Classes
    Dependency Injection
    EntityBeans Made Easy
    Security Annotations

    This article looks at the various new features introduced in the Enterprise JavaBean (EJB) 3.0 specification and how they'll make developing EJBs easier. The main theme of the EJB 3.0 is ease of development, which is the purpose of the new features in this release.

    Using Annotations Instead ofDeploymentDescriptors

    EJB 3.0 uses metadata annotations as an alternative to deployment descriptors. Annotations were introduced in J2SE 5.0 and are a key element in the EJB 3.0 simplification. In EJB 3.0, all Enterprise JavaBeans are Plain Old Java Objects (POJO), with proper annotations. So a developer marks up his/her Java code with annotations and the annotation processor creates the deployment descriptors at runtime. This mechanism allows the deployer to override the default configs so they can replace data sources, etc. Another enhancement here is that the code and annotations are in one file--the developer doesn't have to maintain multiple files for one bean. For example, the following code shows how to define a simple stateless session bean:

    /* Example class for Stateless session */ @Stateless public class MessageStoreBean implements MessageStore{ public String getMessage(){ return "Test Message"; } } /* Example class for Business Interface */ @Remote public interface MessageStore{ public String getMessage(); } 

    The @Stateless annotation marks theMessageStoreBean as a stateless session bean. Furthermore, the @Remote annotation indicates that it's a business interface. But it is not mandatory to writeRemote interfaces: we can use @Remote in the bean class itself to let the container generate the business interface, as in the following example:

    @Stateless @Remote public class MessageStoreBean{ public String getMessage(){ return "Test Message"; } } 

    In the above example, the bean class doesn't implement the business interface, and uses @Remote instead. This makes development much easier than in previous versions. EJB 3.0 provides annotations for every type of metadata previously addressed by deployment descriptors, so no XML descriptor is needed and you can deploy your beans simply by deploying a plain old .jar into your application server.

    This doesn't mean that XML has been completely removed; it's now optional. If we define both a deployment descriptor and annotations, the deployment descriptor overrides the annotations.

    Callback Methods and Listener Classes

    The EJB 2.1 spec required you to implement either the interfacejavax.ejb.SessionBean orjavax.ejb.EntityBean. Methods likeejbCreate(), ejbPassivate(), andejbActivate() were never used in your application and just cluttered up your code. Fortunately, they're not required in EJB 3.0.

    In EJB 3.0, bean developers do not have to implement unnecessary callback methods and can instead designate any arbitrary method as a callback method to receive notifications for lifecycle events for a SessionBean or MessageDrivenBean (MDB). Callback methods can be indicated using callback annotations.

    Also, we can design a callback listener class instead of writing callback methods in the bean class itself. The annotations used for callback methods are the same in both cases--only the method signatures are different. A callback method defined in a listener class must take a Object as a parameter, which is not needed when the callback is in the bean itself. Here's an example of putting a callback in the bean:

    /* Callback method defined inside a bean class */ @Stateful public class TestBean{ private int var; public int method(){} @PreDestroy testMethod(){} } 

    In the above code fragment, we are defining a callback method in the bean class itself. @PreDestroy is one of the callback annotations.

    /* Callback method defined inside a Listener class*/ public class CustomListener{ @PrePassivate public testMethod(Object obj){ // Statements } } /* Adds callback listener to bean class */ @CallbackListener CustomListener @stateful public class TestBean{ private int var; public void getPrice(){} } 

    Here, we are writing a separate listener class for callback methods and have a small difference in method signatures. We must pass an Object parameter, because we're defining the callback listener in a separate class. A bean class adds the callback listener class by using a special callback annotation@CallbackListener.


    The runtime services like transaction and security are applied to the bean objects at the method's invocation time. These services are often implemented as the interceptor methods managed by the container. However, EJB 3.0 allows developers to write the custom interceptor methods that are called before and after the bean method. It is useful to give the control to the developer for the actions like commit transaction, security check, etc. You can develop, reuse, and execute your own services. Or, you can re-implement the transaction and security services to override the container's default behaviors.

    Interceptors offer fine-grained control over method invocation flow. They can be used on SessionBeans (stateful and stateless) and MessageDrivenBeans. They can be defined in the same bean class or in an external class. The interceptor's methods will be called before the actual bean class methods are called.

    The following is the signature of the interceptor method:

    public Object <methodName>(javax.ejb.InvocationContext) throws Exception 

    The interceptor method must take theInvocationContext object. This interface defines the following methods:

    package javax.ejb; public interface InvocationContext{ public Object getBean(); public Method getMethod(); public Object[] getParameters(); public void setParameters(Object params[]); public EJBContext getEJBContext(); public Object proceed() throws Exception; 

    The @Interceptor annotation designates an interceptor defined on another class. If more than one external interceptor is needed, the @Interceptors is used instead.

    The @AroundInvoke indicates the method acts as an interceptor. The interceptors are applied to all business methods for the bean. We can use the interceptor to change the value of bean method's parameter. The following code is an example of an interceptor defined in a bean class itself:

    @StateLess @Interceptor("TestInterceptor") public class LoginBean{ @AroundInvoke public Object testInterceptor(InvocationContext invContext) throws Exception{ invContext.proceed(); } } 

    And here's what an interceptor looks like when defined in an external class:

    public class TestInterceptor{ @AroundInvoke public Object myInterceptor(InvocationContext invContext) throws Exception{ invContext.proceed(); } } 

    Dependency Injection

    Dependency injection is a term used to describe a separation between the implementation of an object and the construction of an object it depends upon. Instead of complicated XML ejb-refs or resource refs, you can use the @Injectannotation to set the value of a field or to call a setter method within your session bean with anything registered within JNDI. EJB 3.0 facilitates this feature by providing annotations to inject the dependencies into the bean class itself. Dependency annotation may be attached to the bean class, instance variables, or methods. The main reason for introducing @Inject is to avoid JNDI lookup to get the resources set the JNDI tree. Also another great effect of using @Inject is to allow a bean to be tested outside of the container.

    Consider the following code:

    @Stateful public class LoginBean implements Login{ @Inject private UserTransaction tx; @Inject private DataSource ds; private ValidateBean validate; @EJB(name = "validateLogin") public void setValidateLogin(ValidateBean validate){ this.validate = validate; } } 

    When an instance of LoginBean is created, the EJB container will look for the values of tx andds in the JNDI tree to assign the instance variables. Also, the container will get the reference for the EJBValidateBean and call thesetValidateLogin() setter method.

    EntityBeans Made Easy

    To create an EntityBean, a developer only needs to code a bean class and annotate it with appropriate metadata annotations. The bean class is a POJO.

    Look at the following example code:

    /* Example program for EntityBeans using annotations */ @Entity public class TestEntityBean{ private String userId; private String name; @id(generate=AUTO) public String getUserId(){ return this.userId; } public void setUserId(String userId){ this.userId = userId; } public String getName(){ return this.name; } public void setName(String name){ this.name = name; } } 

    The @Entity annotation indicates the class is anEntityBean. Unlike in previous versions, in EJB 3.0EntityBeans are not required to have Homeinterfaces, Business interfaces, and deployment descriptors. In EJB 3.0, an EntityBean is a concrete class, not a abstract class, as was the case in EJB 2.1. Of course, this means that methods are concrete and not abstract. We can create an instance of EntityBean using thenew() operator like normal.

    Security Annotations

    EJB 3.0 provides annotations to specify security options. The following are the security-related annotations defined in EJB 3.0:

    • @SecurityRoles
    • @MethodPermissions
    • @Unchecked
    • @Exclude
    • @RunAs

    Annotations applied for package-level elements are called package-level annotations. These annotations are placed in the filepackage-info.java. The security roles are applied to the entire EJB module. The @SecurityRoles annotation must be placed in the package-info.java file with the package information. When the compiler parses package-info.java, it will create a synthetic interface. It does not have any source code, because it is created by the compiler. This interface makes package-level annotations available at runtime. The filepackage-info.java is created and stored inside of every package. For example, if your bean class is inside of the packageejb3.login, then you must put yourpackage-info.java file inside the ejb3.loginpackage with the user role details.

    The package-info.java file is new in J2SE 5.0. It contain package declaration, annotations, package tags and Javadoc tags. It is preferred over the package.html file used in the previous versions, because package.html can contain only package comments and Javadocs, not annotations. A package may contain either package-info.java or package.html, but not both. Place either file in the package directory in the source tree along with your .java files.

    The following example shows how to define a@SecurityRoles annotation:

    @javax,ejb.SecurityRoles(roleNames={"admin",user"}) package oreilly.ejb30; 

    In the above code, we defined two role names: adminand user. We have to use the@MethodPermissions annotation to specify the method permissions for each method, as in the following example:

    import javax.ejb.MethodPermissions; import javax.ejb.StateLess; import javax.ejb.Unchecked; @Stateless @MethodPermissions("admin") public class LoginBean{ public void updateProfile(){ System.out.println("Prifile Updated"); } @MethodPermissions("GUEST") public void login(){ //Statements } @Unchecked public void homePage(){ //Statements } } 

    If we put a @MethodPermisions above the class declaration, it is considered the default security role for all methods in the bean class. A @MethodPermission defined for a specific method will include the default security role as well as whatever permissions it defines. In the above example,admin is the default security role for all the methods.

    In this example, the updateProfile() method can be accessed only by the admin role. Thelogin() method can be accessed by bothadmin and GUEST roles. ThehomePage() method has no restrictions, since@Unchecked implies that anyone can access that method.

    Mapping these security roles to users or groups is done in the application-server-specific XML file. For example, if your are working on Oracle Application Server, you will configure these mappings in the orion-ejb-jar.xml file. See the following example.

    <assembly-descriptor> <security-role-mapping name="GUEST"> <user name="user"/> </security-role-mapping> </assembly-descriptor> 

    Map logical roles defined in the annotations to actual users and groups defined in a user repository. The mapping is specified in the OC4J-specific deployment descriptor with a<security-role-mapping> element. In the above example, the logical role GUEST defined using annotations is mapped to the user named user.


    The proposals made in EJB 3.0 drafts look very promising for enterprise Java developers. This should be a great time for EJB developers to work with the long-awaited new version. Now it's time for application server vendors to implement these specifications and provide a good option for enterprise application development.