How I Learned to Avoid Magical Dependency Injection And Love Plain Java
A short story about the complexity of magical frameworks and dependency injection with a happy ending, featuring Resteasy, CDI, and JBoss.
Once upon time, I have created a JAX-RS webservice that needed to supply data to a user's session. I wanted to be fancy and thus created aa setter an alternative constructor taking the mailbox on each class using it (the service and JSF bean) (using a constructor might be even better).
Result? Actually better testability and simpler code.
Bjørn Borud and Johannes Brodwall were right - plain old Java is better than magical frameworks and magical DI is evil. (Though they would diapprove of JBoss and likely prefered if I used a plain servlet instead of JAX-RS for my very simple case.)
Update: As pointed out by Daniel Kolman now and others previously, dependency injection itself isn't bad (though some would argue), it is only magic DI that is a problem. You can well do DI yourself using plain old Java - see Bakksjø: The inverse of IoC is Control, Perry: Do-It-Yourself Dependency Injection (pdf; quote: "[..] shows how dependency injection can be accomplished without any framework. The same benefits provided by frameworks can be realized using “do-it-yourself” (DIY) handcrafted code."; recommended by Google's test master Miško Hevery who is a fan of DI because it helps with testability).
Once upon time, I have created a JAX-RS webservice that needed to supply data to a user's session. I wanted to be fancy and thus created a
@Singleton
class for the exchange of information between the two (since only a user request serving code can legally access her session, a global data exchange is needed). However sharing the singleton between the REST service and JSF handler wasn't so easy:
- Originally, the singleton was generic:
OneTimeMailbox<T>
- but this is not supported by CDI so I had to create a derived class (annotated with@Named @Singleton
) - While everything worked in my Arquillian test, at runtime I got NullPointerException because the
@Inject
-ed mailbox was null in the service, for reasons unclear. According to the internets, CDI and JAX-RS do not blend well unless you use ugly tricks such as annotating your service with@RequestScoped
(didn't help me) or use JBoss' resteasy-cdi module.
OneTimeMailbox.getInstance()
) while making testing possible with multiple instances by having Result? Actually better testability and simpler code.
Bjørn Borud and Johannes Brodwall were right - plain old Java is better than magical frameworks and magical DI is evil. (Though they would diapprove of JBoss and likely prefered if I used a plain servlet instead of JAX-RS for my very simple case.)
Update: As pointed out by Daniel Kolman now and others previously, dependency injection itself isn't bad (though some would argue), it is only magic DI that is a problem. You can well do DI yourself using plain old Java - see Bakksjø: The inverse of IoC is Control, Perry: Do-It-Yourself Dependency Injection (pdf; quote: "[..] shows how dependency injection can be accomplished without any framework. The same benefits provided by frameworks can be realized using “do-it-yourself” (DIY) handcrafted code."; recommended by Google's test master Miško Hevery who is a fan of DI because it helps with testability).