Java Solaris Communities My SDN Account Join SDN
 
Enterprise Java Technologies Tech Tips

Pitfalls in Constructing Java Persistence Query Language Queries, and
EJB 3.0 Interceptors -- Continued

 
In this issue

Welcome to the Enterprise Java Technologies Tech Tips for December 16, 2006. Here you'll get tips on using enterprise Java technologies and APIs, such as those in Java Platform, Enterprise Edition (Java EE).

This issue covers:

These tips were developed using the Java EE 5 SDK. You can download the SDK from the Java EE Downloads page.

You can download the sample archive for the Pitfalls in Constructing Java Persistence Query Language Queries tip. You can download the sample archive for the EJB 3.0 Interceptors -- Continued tip.

Any use of this code and/or information below is subject to the license terms.

Pitfalls in Constructing Java Persistence Query Language Queries
By Jie Lin Leng  

One of the things that the Java Persistence API specifies is a query language that allows you to define queries over entities and their persistent state. The query language, called the Java Persistence Query Language, gives you a way to specify the semantics of queries in a portable way, independent of the particular database you're using in an enterprise environment.

A recent Tech Tip introduced the Java Persistence Query Language and discussed some of its basic features. The following Tech Tip covers several things to be careful about when you construct Java Persistence Query Language queries. The tip assumes that you understand the basic terms and concepts of the Java Persistence API. If you don't, see "Chapter 24: Introduction to the Java Persistence API" in the Java EE 5 Tutorial.

A sample package accompanies the tip. The code examples in the tip are taken from the source code of the sample (which is included in the package). The sample uses the Java EE 5 SDK. You can download the Java EE 5 SDK from the Java EE Downloads page .

Entities Used in This Tip

Let's start with two persistent entities. These are the same two entities that were used in the Introduction to the Java Persistence Query Language tip. The entities are Customer and Order, and they have a one-to-many relationship. The Customer entity class and the Order entity class are defined as follows:

   @Entity
   @Table(name="CUSTOMER_TABLE")
   public class Customer implements Serializable{

      public enum CustomerStatus 
          {FULL_TIME, PART_TIME, CONTRACT};
      @Id
      @Column(name="ID")
      private Integer customerId;
      @Column(name="CITY")
      private String city;
      @Column(name="NAME")
      private String name;
      @Enumerated(ORDINAL)
      @Column(name="STATUS")
      private CustomerStatus status;
      @OneToMany(mappedBy="customer")
      private <Collection> orders;

      ...
   }

   @Entity
   @Table(name="ORDER_TABLE")
   public class Order implements Serializable {
  
      @Id
      @Column(name="ID")
      private Integer orderId;
      @Column(name="quantity")
      private int quantity;
      @Column(name="totalPrice")
      private float totalPrice;
      @ManyToOne()
      @JoinColumn(name="CUST_ID")
      private Customer customer;
      
      ...
   }

Here's the client code that creates instances of the entities, creates an entity manager to manage their persistence, and inserts the instances in a database:

   // Create an EntityManagerFactory for a persistence unit 
   // called j2seEnvironment.
   EntityManagerFactory emf =
   Persistence.createEntityManagerFactory("j2seEnvironment");

   // Create an Entity Manager
   EntityManager em = emf.createEntityManager();
   
   // get a Transaction
   EntityTransaction tx = em.getTransaction();
   
   // create a POJO instance of the Customer class
   Customer customer = new Customer();
   customer.setCustomerId(new Integer(3));
   customer.setName("SUN_SALE");
   customer.setCity("SAN JOSE");
   customer.setStatus(Customer.CustomerStatus.FULL_TIME);
           
   // create a POJO instance of the Order class 
   // for this customer
   Order order = new Order();
   order.setOrderId(new Integer(3));
   order.setQuantity(new Integer(2));
   order.setTotalPrice(new Float(22.30));
   order.setCustomer(customer);
           
   // Make the Customer and Order instances persistent 
   // and insert them into the database
   tx.begin();
   em.persist(customer);
   em.persist(order);
   tx.commit();

Now let's look at some Java Persistence Query Language queries that sometimes cause problems for developers, and run them against these entities.

Using a LIKE Expression With an Escape Character

The Java Persistence Query Language supports various types of comparison expressions including the LIKE expression. Using a LIKE expression in a Java Persistence Query Language query can be tricky if the expression specifies the backslash character (\) as an escape character.

A LIKE expression determines whether a string matches a pattern.The syntax for a LIKE expression looks like this:

   string_expression LIKE pattern_value [ESCAPE escape_character]

The string_expression must have a string value. It's the string you want to match. The pattern_value is a string literal or a string-valued input parameter. It's the pattern against which you match the string. The pattern_value can include an underscore character (_), which stands for any single character, and a percent character (%), which stands for any sequence of characters. The optional escape character is a single-character string literal or a character-valued input parameter, and is used to escape the special meaning of the underscore and percent characters in the pattern_value.

For example, the following LIKE expression:

   customer.name LIKE 'f_r%'

compares the value of customer.name with a pattern whose first character is "f", whose second character is any character, whose third character is "r", followed by any number of characters. In this case, the expression is true if the value of customer.name is "fore" or "forego" but not if it's "four".

The following LIKE expression:

   customer.name LIKE 'f\_r%' ESCAPE '\'

compares the value of customer.name with a pattern whose first character is "f", whose second character is the underscore character (the backslash is used here to escape the special meaning of the underscore character), whose third character is "r", followed by any number of characters. In this case, the expression is true if the value of customer.name is "f_r" or "f_rst" but not if it's "four", "fore" or "forego".

LIKE expressions that specify the backslash character as an escape character work properly only if you specify a second backslash. That's because the backslash character is also treated by the Java compiler as an escape character. Here's an example:

   // run a Java Persistence query using input parameters
   String ejbql = "SELECT c from Customer c 
                   WHERE c.name LIKE :pattern ESCAPE :esc";
   Query query = em.createQuery(ejbql);
   query.setParameter("pattern", "\\_%");
   query.setParameter("esc", '\\');

As you can see, two backslashes are used in the setParameter() method calls. The first backslash in each method call is processed by the Java compiler and the second backslash is processed by the Java Persistence Query Language compiler. The result is to match a string whose first character is the underscore character.

Here is equivalent code that does not use input parameters:

   String ejbql = "SELECT i FROM Item i 
                  WHERE i.name LIKE '\\_%' ESCAPE '\\'";
   Query query = em.createQuery(ejbql); 

Using an Enumerated Annotation

Programmers sometimes run into problems when they use an Enumerated annotation in combination with the Java Persistence Query Language.

An Enumerated annotation specifies that a persistent property or field should be persisted as an enumerated type. An enum (the base class for all enumerated types) can be mapped as either a string or an integer. There are two enumerated types: ORDINAL and STRING. If the enumerated type is not specified, the enumerated type is assumed to be ORDINAL.

Problems arise if you try to assign a numeric or string value based on an enum type. For example, in entity class Customer, CustomerStatus is an enum. The field status in Customer, defined as CustomerStatus, is mapped to an integer. You might think that the following Java Persistence Query Language query correctly queries customer status:

   String ejbql = "SELECT c FROM Customer c 
                   WHERE c.status = 1";

In fact, the query throws a java.lang.IllegalArgumentException. The exception is thrown because the Java Persistence Query Language compiler is expecting an enum constant.

The correct way to query the customer status is as follows:

   // run a Java Persistence query
   String ejbql = "SELECT c FROM Customer c 
                  WHERE c.status = :status";
   Query query = em.createQuery(ejbql);
   query.setParameter(
      "status", Customer.CustomerStatus.FULL_TIME);

In the correct query an enum constant, Customer.CustomerStatus.FULL_TIME is assigned to the enum field status.

Using an IN operator In a Conditional Expression

An IN operator in a conditional expression determines whether a value is in an item or in a set of items. An NOT IN operator determines whether a value is not in an item or not in a set of items.

The formal syntax for an IN or NOT IN comparison operator in a conditional expression looks like this:

   in_expression ::= state_field_path_expression [NOT] IN 
   (in_item {, in_item}* | subquery) 
   in_item ::= literal | input_parameter

The state_field_path_expression is the expression that contains the value for the comparison, and in_item is the item or set of items against which the value is checked.

For example, the expression o.country IN ('UK', 'US', 'FRANCE') is true if the value of o.country is UK, and false if the value of o.country is PERU. The expression o.country NOT IN ('UK', 'US', 'FRANCE') is false if the value of o.country is UK, and true if the value of o.country is PERU.

When you use an IN or NOT IN operator in a conditional expression, you need to keep the following in mind:

  • The state_field_path_expression must have a string, numeric, or enum value. Other types are not supported.
  • The item or set of items in in_item must have the same type as the state_field_path_expression.
  • The result of the subquery must have the same type as the state_field_path_expression.

Here are some working examples:

   // IN with subquery 
   String ejbql = "SELECT o FROM Order o 
                  WHERE o.customer.name 
                  IN (SELECT c.name 
                  FROM Customer c WHERE c.customerId = 3)"; 
                  Query query = em.createQuery(ejbql); 
                      
   // IN with set of integers 
   String ejbql = "SELECT o FROM Order o 
                  WHERE o.customer.name IN (2, 3)"; 
                  Query query = em.createQuery(ejbql); 
                  
   // IN with set of strings 
   String ejbql = "SELECT o FROM Order o 
                  WHERE o.customer.name IN ('foo', 'JIE_LENG')"; 
                  Query query = em.createQuery(ejbql);

Using Native Queries

The Java Persistence Query Language supports native queries. In other words, you can express a Java Persistence Query Language query using the SQL of the target database. Native queries are not guaranteed to be portable across databases.

The result of a native query can consist of entities, scalar values, or a combination of entities and scalar values.

When multiple entity types are returned by a native query, the entities must be specified and mapped to the column results of the SQL statement in a @SqlResultSetMapping annotation. The result set mapping metadata can then be used by the persistence runtime to map the JDBC results into the expected objects.

Here is an example in which a native SQL query returns entities of a single entity class. The entity class that specifies the type of the result is passed in as an argument. Because the native query returns a single entity type it does not require a @SqlResultSetMapping annotation. When executed, this query returns a Collection of all Order entities for the customer named "SUN_SALE".

   Query q = em.createNativeQuery(
            "SELECT o.id, o.quantity, o.customer " + 
             "FROM Order o, Customer c " + 
             "WHERE (o.customer = c.customerId) 
               AND (c.name = 'SUN_SALE')", 
                   ejbql.models.Order.class); 
   List orders = q.getResultList();

The following query returns multiple entity types and so it requires a @SqlResultSetMapping annotation. The example assumes default metadata and column name defaults. Note that the @SqlResultSetMapping annotation always needs to be specified before the entity class definition.

   @SqlResultSetMapping(name="OrderCustomerResults", 
      entities={ @EntityResult(
        entityClass=ejbql.models.Order.class), 
   @EntityResult(entityClass=ejbql.models.Customer.class) } ) 
   @Entity public class Order { ... }

The following code executes the native query:

   Query q = em.createNativeQuery( 
      "SELECT o.id, o.quantity, c.customerId, c.name, c.city " + 
      "FROM Order o, Customer c " + 
      "WHERE (o.quantity > 25) 
        AND (o.customer = c.customerId)", 
            "OrderCustomerResults"); 
   List result = q.getResultList();
   
   int s = result.size(); 
   for(int i = 0; i < s; i++){ 
       Object obj = result.get(i); 
       Object[] objectArray = (Object[]) obj; 
       Object object1 = objectArray[0]; 
       Object object2 = objectArray[1]; 
       Order order = (Order) object1; 
       Customer customer = (Customer)object2; 
   }

Using NULL Values

It's important to keep the following in mind if you use a NULL value in a Java Persistence Query Language query:

  • 'IS NULL' and '= NULL' have different semantics.
  • Comparison or arithmetic operations with a NULL value always yield an unknown value.
  • Two NULL values are not considered to be equal, the comparison yields an unknown value.

So the following query:

   String ejbql = "SELECT c FROM Customer c 
                   WHERE c.name = NULL";
   Query query = em.createQuery(ejbql);

does not return any customers, even if there are customers who do not have a name. The reason is that the expression customer.name = NULL does not evaluate to true if the name is null. It evaluates to an unknown value. This is also the case for a query using an input parameter if you set the value of the input parameter to null.

The correct syntax for checking whether or not a singled-valued path expression or input parameter is a NULL value is:

   {single_valued_path_expression | input_parameter} 
   IS [NOT] NULL

For example, the following query:

   String ejbql = "SELECT c FROM Customer c 
                  WHERE c.name IS NULL";
   Query query = em.createQuery(ejbql);

returns all the customers that do not have a name.

For More Information

The Java Persistence Query Language is a full structured query language and includes language features for bulk update and delete operations, outer join operations, projection, and subqueries. For a description of the language see "Chapter 27: The Java Persistence Query Language" in the Java EE 5 Tutorial.

Running the Sample Code

To install and run the sample code that accompanies this tip:

  1. If you haven't already done so, download Java EE 5 SDK from the Java EE Downloads Page, and install it.

  2. Set the following environment variables:
    • JAVAEE_HOME. This should point to where you installed the Java EE 5 SDK.
    • ANT_HOME. This should point to where ant is installed. Ant is included in the Java EE 5 SDK bundle that you downloaded. (In Windows, it's in the lib\ant subdirectory.)
    • JAVA_HOME. This should point to the location of JDK 5.0 on your system. JDK is included in the Java EE 5 SDK bundle that you downloaded. (In Windows, it's in the jdk subdirectory.)
    Add $JAVA_HOME/bin, $ANT_HOME/bin, and $JAVAEE_HOME/bin to your PATH environment variable.

  3. Download the sample package and extract its contents. The JPQL directory below ttdec2006jpql contains the source files and other support files for the sample.

  4. Change to the JPQL directory and edit the build.xml file as appropriate. For example, set the value of javaee.home to where you installed the Java EE 5 SDK.

  5. Start database server:

       $JAVAEE_HOME/bin/asadmin start-database

  6. In response you should see output similar to this:

                ...

          start-db:
               [exec] Database started in Network Server mode on host 
               ... and port ...
          
               [exec] Starting database in the background.  Log 
               redirected to ...
               [exec] Command start-database executed successfully. 


  7. Build and run the sample application. From the JPQL directory enter the following command:

       ant all

    In response you should see output produced by the Java Persistence Query Language queries shown in this tip. The output should look similar to this:

       ...
       
            [java] JPQL query for LIKE/ESCAPE with named parameters 
       SELECT c from Customer c WHERE c.name LIKE :pattern ESCAPE :e
       sc returns Customers: [ejbql.models.Customer@1264eab, ejbql.m
       odels.Customer@1e184cb]
            [java] JPQL query for LIKE/ESCAPE SELECT c FROM Customer 
       c WHERE c.name LIKE 'SUN\_%' ESCAPE '\' returns Customers: [e
       jbql.models.Customer@1264eab, ejbql.models.Customer@1e184cb]
            [java] JPQL query for ENUMERATED type SELECT c FROM Cust
       omer c WHERE c.status = :status returns Customers: [ejbql.mod
       els.Customer@1e184cb]
            [java] JPQL query for IN subquery SELECT o FROM Order o 
       WHERE o.customer.name IN (SELECT c.name FROM Customer c WHERE 
       c.customerId > 2) returns Orders: [ejbql.models.Order@1a99347
       , ejbql.models.Order@221e9e]
       ...
            
            [java] JPQL query for Native Query SELECT o FROM Order o 
       WHERE o.customer.name IN ('foo', 'SUN_SALE') returns Orders: 
       [ejbql.models.Order@1a99347]
       ...
       
            [java] JPQL query for NULL handling SELECT c FROM Custom
       er c WHERE c.name IS NULL returns Customers: []   
         

About the Author

Jie Lin Leng is a member of the Java Persistence Engineering group at Sun. She is currently involved in the development of the Java Persistence Query Language for EJB 3.0.

EJB 3.0 Interceptors -- Continued
By Mahesh Kannan  

One of the new features introduced in the EJB 3.0 specification is interceptors. An interceptor is a method that you can interpose in the invocation flow of an enterprise bean. You can define an interceptor to intercept an enterprise bean's business methods -- the interceptor method runs before any of the bean's business methods are invoked. Or you can define an interceptor to intercept lifecycle events for an enterprise bean -- the interceptor method runs as a callback method for the bean's lifecycle events.

A recent Tech Tip introduced the concept of EJB 3.0 interceptors and described how to write multiple interceptors and chain them together. The following Tech Tip discusses how to add interceptors at the method level and further discusses interceptor ordering.

A sample package accompanies the tip. The code examples in the tip are taken from the source code of the sample (which is included in the package). The sample uses the Java EE 5 SDK. You can download the Java EE 5 SDK from the Java EE Downloads page.

An Example Bean

To demonstrate the concepts in this tip, let's use a simple stateless session bean named NumberUtilbean. The bean provides a set of simple utility methods, and implements a business interface named NumberUtil.

Here is what umberUtil looks like:

   package com.sun.techtip2.interceptor;
   
   import javax.ejb.Remote;
   
   @Remote
   public interface NumberUtil {
   
      public byte[] intToBytes(int val);
      
      public int bytesToInt(byte[] data);
      
      public boolean isOddNumber(int val);
      
   }
   

And here is NumberUtilBean:

   package com.sun.techtip2.interceptor;
   
   import javax.ejb.Stateless
    
   @Stateless 
   public class NumberUtilBean
      implements NumberUtil {
 
      public byte[] intToBytes(int val) {...}
      
      public int bytesToInt(byte[] data) {...}
      
      public boolean isOddNumber(int val) {...}
      
   }

Note that the isOddNumber method is so trivial that it could have been implemented in client code. However, to demonstrate interceptors the method is included in the remote interface.

Class Level Interceptors

The previous tip showed how to define an interceptor and add it to a bean. It included as an example of an interceptor, a method profiler that prints the time it takes to run an intercepted business method. Let's create another method profiler that will be used as an interceptor. The new method profiler prints the time taken by each of the methods in NumberUtilBean

As explained in the previous tip, you define an interceptor with an @AroundInvoke method, and you can add the interceptor to a class using the @Interceptors annotation. Adding the interceptor at the class level ensures that the interceptor's around invoke methods are invoked before every business method in the class.

Here is the new method profiler, MethodProfileInterceptor:

   package com.sun.techtip2.interceptor;
   
   import javax.interceptor.AroundInvoke;
   
   public class MethodProfileInterceptor {
   
       public MethodProfiler () {
       }
   
       @AroundInvoke
       private Object recordStat(InvocationContext invCtx)
           throws Exception {
           long t1 = System.currentTimeMillis();
           try {
               invCtx.proceed();   //Continue execution
           finally {
               long t2 = System.currentTimeMillis();
               System.out.println(invCtx.getMethod().getName() + 
               " took: " + ((t2 - t1)/1000.0 + " seconds");
           }
       }
   }

Here is NumberUtilBeanwith the new interceptor added to the class:

   package com.sun.techtip2.interceptor;
   
   import javax.ejb.Stateless
   import javax.interceptor.Interceptors;
   
   @Interceptors(
        {com.sun.techtip2.interceptor.MethodProfileInterceptor.class})
   @Stateless
   public class NumberUtilBean
      implements NumberUtil {
 
      public byte[] intToBytes(int val) {...}
      
      public int bytesToInt(byte[] data) {...}
      
      public boolean isOddNumber(int data) {...}
      
   }   

Method Level Interceptors

Say you want to add an interceptor to NumberUtilBean that checks if an argument passed to its methods is null or not. You can easily add the interceptor to the class using the @Interceptors annotation. In this case, the interceptor's around invoke method is invoked before each bean method.

But what if you want to restrict the interceptor to a specific method in the bean? For example, suppose you want to validate that the parameter passed to the intToBytes() method in NumberUtilBean is not null. To do that, you need to specify the @Interceptors annotation at the method level rather than at the class level. This ensures that the interceptor's around invoke method is invoked only before the specific method.

Here is the code for an interceptor that checks if a parameter is not null:

   import javax.interceptor.AroundInvoke;
   
   public class NumberUtilArgumentsChecker {
   
       public NumberUtilArgumentsChecker() {
       }
   
       @AroundInvoke
       private Object validate(InvocationContext invCtx)
           throws Exception {
       
           Object[] params = invCtx.getParameters();
           if (params.length == 0) {
               throw new IllegalArgumentException(
                   invCtx.getMethod().getName()
                   + "Requires a non null argument");
           }
           
           return invCtx.proceed();
           
       }  

Notice how invCtx.getMethod().getName() is used to get the method name, which is added to the exception text if the parameter is null.

Here is the NumberUtilBean with the new interceptor added for the intToBytes() method:

   package com.sun.techtip2.interceptor;
   
   import javax.ejb.Stateless
   import javax.interceptor.Interceptors;
   
   @Interceptors(
    {com.sun.techtip2.interceptor.MethodProfileInterceptor.class})  
   @Stateless
   public class NumberUtilBean
      implements NumberUtil {
 
      public byte[] intToBytes(int val) {...}
      
      @Interceptors(
       {com.sun.techtip2.interceptor.NumberUtilArgumentsChecker.class})
      public int bytesToInt(byte[] data) {...}
      
      public boolean isOddNumber(int data) {...}
      
   }

Changing the Invocation Order of Interceptors

It's possible to have a class in which interceptors are defined at both the class level and the method level. In that case, it's important to know the order in which the interceptors are invoked. The EJB 3.0 specification declares the following invocation order if both class-level and method-level interceptors are specified:

  1. Any interceptor classes defined on the bean class. These class-level interceptors are invoked in the order that they are specified in the @Interceptors annotation.
  2. Any interceptors that are specified at the method level. These method-level interceptors are invoked in the order that they are specified in the @Interceptors annotation.
  3. The interceptor method on the bean, if any.

Excluding Interceptors

In the method profiler example, the class-level interceptor, MethodProfileInterceptor, is run before all the methods in the NumberUtilbean class, including the isOddNumber() method. However the implementation of isOddNumber() is so trivial that it doesn't really need any profiling.

You could exclude the interceptor from running before the isOddNumber() method by removing it as a class-level interceptor and explicitly specifying it as method interceptor for only the intToBytes() and byteToInt() methods.

But there is an easier way to exclude interceptors from a method. You can use the @ExcludeClassInterceptors annotation to exclude class-level interceptors from a specific method. Let's use the @ExcludeClassInterceptors annotation to prevent MethodProfileInterceptor from being executed before the isOddNumber() method.

Here is the NumberUtilBean with the addition of the @ExcludeClassInterceptors annotation:

   package com.sun.techtip2.interceptor;
   
   import javax.ejb.Stateless;
   import javax.interceptor.Interceptors;
   import javax.interceptor.ExcludeClassInterceptors;
     
   @Interceptors(
     {com.sun.techtip2.interceptor.MethodProfileInterceptor.class})
   @Stateless
   public class NumberUtilBean
      implements NumberUtil {
 
      public byte[] intToBytes(int val) {...}
      
      @Interceptors(
        {com.sun.techtip2.interceptor.NumberUtilArgumentsChecker.class})
      public int bytesToInt(byte[] data) {...}
      
      @ExcludeClassInterceptors
      public boolean isOddNumber(int data) {...}
      
   }

Now MethodProfileInterceptor will be invoked only before the intToBytes() and bytesToInt() methods are run.

Running the Sample Code

  1. If you haven't already done so, download Java EE 5 SDK from the Java EE Downloads Page, and install it.

  2. Download the sample package to the <appsrv_install>/samples/javaee5/enterprise directory, where <appsrv_install> is where you installed the Java EE 5 application server. Ensure that you set up your environment as described in the <appsrv_install>/samples/javaee5/index.html file.

  3. Extract the contents of the sample package:

       jar xvf ttdec2006intrcpt_2.jar

  4. Change to the interceptor_2 directory. The directory contains the source files and other support files for the sample.

  5. Start the Application Server by entering the following command:

       <appsrv_install>/bin/asadmin start-domain domain1

  6. Build and run the sample application. From the interceptor_2 directory enter the following command:

          ant all
       }
       bpp-run-app-client:
            [echo] running application client container.
            [exec] intToBytes(1234) ==> 0 0 4 -46
            [exec] bytesToInt(intToBytes(1234))) ==> 1234
            [exec] isOddNumber(7) ==> true

Summary

EJB 3.0 interceptors give you an elegant way to extend the functionality of enterprise beans. They are especially useful for implementing crosscutting operations in a portable way.

A previous Tech Tip introduced interceptors and demonstrated the use of a class-level interceptors. Class-level interceptors are executed before every business method in a bean. This tip introduced method-level interceptors and demonstrated how these interceptors are executed for a specific method in addition to class-lLevel interceptors.

The tip also showed how to use the @ExcludeClassInterceptors annotation, which provides an elegant way to exclude class-level interceptors from executing before a specific method.

There are more advanced topics related to EJB interceptors, such as default interceptors and excluding default interceptors. Also, interceptors can declare dependency injection. This allows the container to inject resources and enterprise beans into interceptors.

About the Author

Mahesh Kannan is member of the EJB container team. He has been involved with Java EE development for the last 6 years.

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.