I had to publish this, just in case others are suffering from the same problem and losing their sanity…
At some moment during development, Glassfish refused to start a JEE 6 app with the following error:
Just that, no other error messages, no stack trace or exception, no nothing.
After a lot of tinkering in the dark I found that this happened when the CDI implementation packed with Glassfish (Weld) found some problems. In my case, whenever Weld could not @Inject a remote bean with a @Remote interface using the following code:
@Inject private UserRepository userRepository
Of course, that can’t work unless you provide the JNDI lookup. My mistake, I just didn’t pay attention because I was developing all modules in the same Eclipse project to minimize time to deploy, and forgot the remoting tax.
Of course, using the @EJB annotation worked when I specified the JNDI lookup as follows:
@Ejb(lookup="java:global/bkc-all/userRepositoryBean") private UserRepository userRepository
Why does @Inject not work here? Well, in order to perform an @Inject, CDI uses metadata to get the information needed to resolve the bean. But, for a remote bean, there is no such metadata at hand to the program, the implementation lives in outer space, in a remote VM.
Of course, the solution to keep using @Inject is to define a producer field that specifies how to locate the remote bean, as follows:
@Produces @Ejb(lookup="java:global/bkc-all/userRepositoryBean") @RemoteBean private UserRepository userRepositoryProducer;
Then, whenever CDI finds an injection point like the following one, it will work
@Injection private UserRepository userRepository;
Back to the problem…Ok, my mistake, but here Weld/Glassfish might have helped a lot by providing a better messsage, even “Weld could not resolve a bean” would have been better than the “something happened”-like message I got.
I was so mistified that at some moment I thought the problem was due to classloading issues, and attempted all sorts of crazy unrelated things!
Why @Inject, and not @EJB?
Now, why use @Produces + @Inject instead of just @EJB, a much shorter version? Because by using @Inject and the @Produces annotation we separate the what (I want the X bean) from the how (the X bean is located in this and that way), and that is key to effective abstraction and encapsulation.
This separation of concerns makes using @Inject the best way to inject beans, backed by @Produces to define how to get them: forget about @EJB, @PersistenceContext, etc. for injection, those are there to help define the how, and only that. Of course, hello world programs need not apply!
My misunderstandings with Glassfish/Weld did not end there, though…
At some moment I refactored a class, changing its name, and then Glassfish started complaining with the following error at runtime whenever I called a EJB method:
Unexpected remote application exception:
javax.ejb.AccessLocalException: Client not authorized for this invocation
java.rmi.AccessException: CORBA NO_PERMISSION 9998 Maybe; nested exception is: org.omg.CORBA.NO_PERMISSION: vmcid: 0x2000 minor code: 1806 completed: Maybe
And, no, I had not been tinkering with security, nor with remote or local interfaces.
A real mistery, as it seemed to be caused by some error attempting to access a remote bean via a @Local interface or something like that…
Well, no sir. It was caused by changing the class name for the remote EJB implementation (?). Bizarre! Symptoms and causes have no relation whatsoever, at least to my mind.
To make matters worse, the only workaround was to remove the app and reconfigure and redeploy it (??).
Admittedly, that is not something you do often if you are trying to do agile development: I use Eclipse and an exploded project structure + directory based Glassfish deployment to minimize time from code change to code execution, so no redeployment should be needed.
That setup is very valuable because sometimes you can change code and keep executing the app, instead of waiting ages to recompile the app, generate the jars, wars, ears and what else.
This generate & pack the whole universe approach that seems almost unavoidable with JEE projects is evil for productivity. We are almost forced into the Maven-based TDD paradigm, TDD standing for Time to Deploy is a Disaster here.
Frankly, sometimes I really doubt there is much people doing TDD out there for enterprise apps, when you see how lousy tool support for zero-time code changes is and how much time it takes to get feedback.
Because one or two minutes is a lot of time when it comes to your train of thought.