views:

350

answers:

2

Is it possible to tell Guice to call some method (i.e. init()) after instantinating an object of given type?

I look for functionality similar to @PostConstruct annotation in EJB 3.

+3  A: 

Actually, it is possible.

You need to define a TypeListener to get the functionality going. Something along the lines of the following in your module definition:

bindListener(Matchers.subclassesOf(MyInitClass.class), new TypeListener() {
    @Override
    public <I> void hear(final TypeLiteral<I> typeLiteral, TypeEncounter<I> typeEncounter) {
        typeEncounter.register(new InjectionListener<I>() {
            @Override
            public void afterInjection(Object i) {
                MyInitClass m = (MyInitClass) i;
                m.init();
            }
        });
    }
});
gpampara
Also an option is to use GuicyFruit, which claims to support @PostConstruct (see http://code.google.com/p/guiceyfruit/), and while it doesn't answer this question, I think it is worth mentioning that if you (solely) use constructor injection, you don't need such functionality as you can do all initialization in the constructor.
Eelco
saved my day. @PostConstruct is not supported by guiceyfruit yet
Boris Pavlović
+1  A: 

guiceyfruit does what you're after for methods annotated with @PostConstruct or implementing spring's InitializingBean. It's also possible to write your own listeners to do this. Here's an example that calls a public init() method after objects are created.


import com.google.inject.*;
import com.google.inject.matcher.*;
import com.google.inject.spi.*;

public class MyModule extends AbstractModule {
  static class HasInitMethod extends AbstractMatcher> {
    public boolean matches(TypeLiteral tpe) {
      try {
        return tpe.getRawType().getMethod("init") != null;
      } catch (Exception e) {
        return false;
      }
    }

    public static final HasInitMethod INSTANCE = new HasInitMethod();
  }

  static class InitInvoker implements InjectionListener {
    public void afterInjection(Object injectee) {
      try {
        injectee.getClass().getMethod("init").invoke(injectee);
      } catch (Exception e) {
        /* do something to handle errors here */
      }
    }
    public static final InitInvoker INSTANCE = new InitInvoker();
  }

  public void configure() {
    bindListener(HasInitMethod.INSTANCE, new TypeListener() {
      public  void hear(TypeLiteral type, TypeEncounter encounter) {
        encounter.register(InitInvoker.INSTANCE);
      }
    });
  }
}
Geoff Reedy