I recently made a mistake to new an object (MethodInterceptor
) in an plain old way in a Guice configuration,
which caused the object’s @Inject
-annotated fields, like Logger
for example, were initialized with null
value.
public class FooInterceptor implements MethodInterceptor{
@Inject
private Logger logger;
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// NPE if logger not inject correctly
logger.info("start to invoke");
return invocation.proceed();
}
}
public class BarModule extends AbstractModule {
@Override
protected void configure() {
bindInterceptor(Matchers.subclassesOf(OrderApi.class),
Matchers.any(),
// new the interceptor in the plain old way
new FooInterceptor());
}
}
Solution
Guice wiki clearly states that requestInjection()
should be used for injection of a “method interceptor”.
How do I inject a method interceptor?
In order to inject dependencies in an AOP MethodInterceptor, use requestInjection() alongside the standard bindInterceptor() call.
public class NotOnWeekendsModule extends AbstractModule {
protected void configure() {
MethodInterceptor interceptor = new WeekendBlocker();
// for injection of a "method interceptor"
requestInjection(interceptor);
bindInterceptor(any(), annotatedWith(NotOnWeekends.class), interceptor);
}
}
Some Thoughts
Once you decide to use a dependency injection framework, like Guice here, please DO NOT new Java objects in the plain old way any more. Otherwise, you may very possibly fail to set up the objects’ dependencies correctly.
Secondly, use constructor-injection for mandatory dependency, like Logger
here.
It’s impossible to forget to inject a dependency using constructor-injection, even if that object is constructed in the plain old way.
(However, too many dependencies injected via the constructor makes the constructor look a bit ugly.)