Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting a static EJB, nonsense?

I want to write this piece of code :

@Stateless
public class MyEjb
{
    @EJB
    private static MyOtherEjbWhichIWantStatic myOtherEjb;
}

It makes sense to me, that I want to inject an EJB in my class, as a static element, for various reason.

Java is not very happy with that unfortunately

com.sun.enterprise.container.common.spi.util.InjectionException: Illegal use of static field private static MyOtherEjbWhichIWantStatic myOtherEjb on class that only supports instance-based injection

I don't get it, why can't I inject a static EJB into another EJB ?

like image 606
Cyril Gandon Avatar asked Jul 07 '10 13:07

Cyril Gandon


2 Answers

As others pointed out, this is not allowed by the specification, and the short version is that the @EJB annotation is only supported for static members in classes with a main() function (see the EJB 3.0 specification and the app client container).

Why is it so? First of all, read/write static fields are totally forbidden in EJBs (this is part of the EJB restriction). From Why can't I use nonfinal static fields in my enterprise bean?

Nonfinal static class fields are disallowed in EJBs because such fields make an enterprise bean difficult or impossible to distribute. Static class fields are shared among all instances of a particular class, but only within a single Java Virtual Machine (JVM). Updating a static class field implies an intent to share the field's value among all instances of the class. But if a class is running in several JVMs simultaneously, only those instances running in the same JVM as the updating instance will have access to the new value. In other words, a nonfinal static class field will behave differently if running in a single JVM, than it will running in multiple JVMs. The EJB container reserves the option of distributing enterprise beans across multiple JVMs (running on the same server, or on any of a cluster of servers). Nonfinal static class fields are disallowed because enterprise bean instances will behave differently depending on whether or not they are distributed.

It is acceptable practice to use static class fields if those fields are marked as final. Since final fields cannot be updated, instances of the enterprise bean can be distributed by the container without concern for those fields' values becoming unsynchronized.

But while using read-only static fields is allowed, this wouldn't be appropriate for EJBs. Stateless EJBs may be pooled, a container may decide to destroy them (this is implementation specific) and you want to let the container choose which instance you're going to use, especially in distributed environments. In other words, never assume you are tied to a particular instance.

So at the end, yes, this is a nonsense.

like image 146
Pascal Thivent Avatar answered Sep 29 '22 19:09

Pascal Thivent


I don't get it, why can't I inject a static EJB into another EJB ?

Because the spec does not allow it:

5.2.3Annotations and Injection

As described in the following sections, a field or method of certain container-managed component classes may be annotated to request that an entry from the application component’s environment be injected into the class. [...] For all classes except application client main classes, the fields or methods must not be static.

Note that the exception (application client main classes) only exists because those classes are never instantiated. Basically, static fields are generally problematic, and doubly so in an application server, because they can circumvent the separation of request handling threads and transactions, which are the whole point of using an application server in the first place.

like image 39
Michael Borgwardt Avatar answered Sep 29 '22 17:09

Michael Borgwardt