Java EE 5.0 brings dependency injection into mainstream. The coolest thing about Java EE 5.0 is that you can use annotations to use injection of resources and EJB.
Recently I got few questions from customers how is the resource name translated into JNDI names when using javax.annotation.Resource annotation. They complained they are getting NameNotFoundException when using Resource annotation.
The Java EE 5.0 spec defines dependency injection in Chapter 5 (EE 5). The javax.annotation.Resource is defined by the JSR-250 (Common Annotations API) . Reading thru the spec and translating the JNDI name for resources may be challenging for many because it's not easy for everyone to weed thru big volumes of specifications.
I must state that most of customer issues I dealt during the early adoption of J2EE, almost 20-25% were related to JNDI. I'm always of the opinion almost half of complexity of EJB and Java EE may be attributed to JNDI.
Using Resource annotation to Inject Resources
Let us start with a simple example, that I've a simple EJB bean (oracle.ejb30.HelloWorldBean) that injects a resource as follows:
@Resource private DataSource fooDS;
It translates to JNDI name "java:comp/env/oracle.ejb30.HelloWorldBean/fooDS"
It is evident from the example that the JNDI name is derived from the fully qualified name of the bean class and variable or setter method being injected to.
Hence you must have a DataSource with JNDI name oracle.ejb30.HelloWorldBean /fooDS configured in your J2EE server otherwise when a bean instance is created you will get NameNotFoundException.
If you think in old way then it is same as specifying as following except that the container will do the injection of the resource to the field:
<resource-ref>
<res-ref-name>oracle.ejb30.HelloWorldBean/fooDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
If you want the resource is to be a logical name and you want to be mapped to a different real JNDI name then you must define the mapping between the logical name to an actual JNDI location in your vendor specific deployment descriptor. Following is an example, how can you do the mapping in Oracle's proprietary descriptor where we use the location attribute to the actual JNDI name for a DataSource e.g. jdbc/OracleDS
<resource-ref-mapping name="oracle.ejb30.HelloWorldBean/fooDS" location="jdbc/OracleDS" />
The above method could be error-prone and probably you will want to inject the resource with JNDI a specific name e.g. jdbc/OracleDS. Then you have to define the resource injection as follows:
@Resource(name="jdbc/OracleDS”) private DataSource fooDS;
Updated:
If you want to do the mapping to a vendor specific global JNDI name using the Resource annotation (instead of using descriptor) then you can use the mappedName element of Resource annotation as follows:
@Resource(mappedName="jdbc/OracleDS”) private DataSource fooDS;
Using JNDI lookup with Resource annotation
The other way you can use a Resource annotation is just specify dependency on the resource such as DataSource and then use a JNDI lookup as in the example below. This is similar to use deployment descriptor to define resource-ref.
First we define the Resource reference at the bean level and then do a JNDI lookup as in the following example:
@Resource(name="jdbc/OracleDS",type=javax.sql.DataSource.class)
@Stateless
public class HelloWorldBean implements HelloWorld {
…
void test()
{
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/OracleDS");
Connection con = ds.getConnection();
…
}
catch (Exception e)
{e.printStackTrace();}
}
..
}
Hope this helps solve the confusion surrounding of use of Resource annotation!
8:35:20 AM
|