Java EE 7: How-to inject an EJB into a WebSocket ServerEndpoint?

9.6k views Asked by At

To sum up my failing project: My @ServerEndpoint class is packaged in a WAR together with the beans.xml file. My WAR in turn is packaged in a EAR and this EAR file is what gets deployed to a GlassFish 4 server that internally use Tyrus.

Should it be possible?

The WebSocket specification says:

Websocket endpoints running in the Java EE platform must have full dependency injection support as described in the CDI specification. Websocket implementations part of the Java EE platform are required to support field, method, and constructor injection using the javax.inject. Inject annotation into all websocket endpoint classes, as well as the use of interceptors for these classes.

The only thing I can understand of this paragraph is that injecting an Enterprise JavaBean into a WebSocket should be no rocket science. However, for me, whatever I do, it fails to work. I feel that most intuitively one should only need to prefix a server endpoint instance field with the @EJB or @Inject annotation, but no one of these annotations work. The variable will be null.

Already a known problem?

One Internet source says a bit cryptically that "due to a bug" he must use constructor injection. I saw that he had added the annotation @Named to the server endpoint. I used the famous copy paste pattern and did exactly what he did, with and without the @Named annotation, and it still don't work. In fact, my @Inject annotated constructor is never even called!

The Tyrus user guide says that one can mix together anyone of the famous session bean declaration annotations with the server endpoint (@Stateful, @Stateless and @Singleton). So I did, still the injection fails to happen. It doesn't matter if I use the annotation @Inject or @EJB.

And that is strange, because the book Java EE 7 Developer Handbook claims to have a working example on page 27 and page 28 based on the same approach. Author Peter Pilgrim annotates his server endpoint @Stateless. He then uses @Inject to do the injection. He says:

In Java EE 7 we must also declare [our server endpoint] as a stateless EJB with @Stateless in order to inject [another EJB] as a dependency. (This is a consequence of Java for WebSocket 1.0 specification.) Note that we can use @javax.annotation.Inject from CDI.

Okay so he says we must use a @Stateless annotation, and "notes" that one can use @Inject. For me, it sounds utterly strange that we "must" use a @Stateless annotation on a server endpoint which according to the specification, is everything else than stateless (!). I've read elsewhere on the Internet that using @Inject instead of @EJB should be one fix. Peter "notes" that "we can use" @Inject but it smells fishy, as if he never got @EJB to work at all and now tries to flee responsibility.

Well, whatever the reason ("bug" or "consequence of the specification"), I couldn't get my dependency injection to work whatever vivid mix of annotations I used on the endpoint class itself or on the instance field.

The ultimate fix

Is to programmatically use a JNDI lookup, but it looks ugly and should be avoided.

2

There are 2 answers

0
Pavel Bucek On BEST ANSWER

(just restating what I wrote into comment to get this question from "unanswered" list)

You should checkou out Tyrus CDI sample/test.

It demonstrates list what you can do with current implementation. We are always open for new test cases, but there are some issues with the spec itself - standard Request scopes don't work for WebSocket runtime, because it handles messages outside of servlets service/doFilter methods. See WEBSOCKET_SPEC-196 and WEBSOCKET_SPEC-197.

5
Sely Lychee On

For me. annoting the websocket with @Stateful and EJB object declaration with @EJB did the work.

@Stateful
@ServerEndpoint(value = "/profileregistration")
public class ProfileRegistrationEndpoint {


@EJB
private ProfileRegistration profileRegEJB;
....
}