harto
harto

Reputation: 90513

Post-injection initialisation (JSF 1.2 + Guice)

I'm trying to integrate Guice into a JSF 1.2 (Sun RI) application, and I want to be able to do the following to my managed-beans:

  1. Inject dependencies using the Guice @Inject annotation, then
  2. Perform initialisation using the @PostConstruct annotation

My problem is that the @PostConstruct method is always invoked before the @Inject annotations are processed. Does anyone know of a solution to this problem?

The managed-bean:

public final class Foo {

    @Inject private BazService bazService;
    private Baz baz;

    @PostConstruct
    public void init() {
        bar = bazService.loadBaz();
    }

    public void setBazService(BazService bazService) {
        this.bazService = bazService;
    }
}

The managed-bean declaration:

<managed-bean>
  <managed-bean-name>foo</managed-bean-name>
  <managed-bean-class>bean.Foo</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
  <managed-property>
    <property-name>id</property-name>
    <value>#{param.id}</value>
  </managed-property>
</managed-bean>

The Guice bindings:

public final class MyGuiceModule extends AbstractModule {

    @Override
    protected void configure() {
        bind(BazService.class).to(DummyBazService.class).in(Scopes.SINGLETON);
    }
}

I've tried the following:

I'm happy to consider other options if this appears to be the wrong way of approaching things... Any help appreciated.


Edit

I was using Guice 1.0. I've now upgraded to Guice 2.0 but the problem remains. I've found some discussion that seems to relate to my issue... but I don't understand how to use this information :(

Upvotes: 2

Views: 3103

Answers (3)

emmby
emmby

Reputation: 100462

This answer seems to have a good solution to how to solve this problem. Specifically, it suggests using the @Inject annotation on an init() method, which is guaranteed to get call after your constructor is called. Note that it may not work if you're using property injection.

Upvotes: 0

NamshubWriter
NamshubWriter

Reputation: 24306

After doing a bunch of reading, I've reached the conclusion that in might be best to avoid @PostConstruct if you use JSF and Guice.

In the example you gave, you can inject Baz:

public final class Foo {

    @Inject private Baz baz;
}

If Baz can't be created by Guice, but must be created by BazService, you can use a provider method:

public final class MyGuiceModule extends AbstractModule {

    @Override
    protected void configure() {
        bind(BazService.class).to(DummyBazService.class).in(Scopes.SINGLETON);
    }

    @Provides
    Baz provideBaz(BazService bazService) {
        return bazService.loadBaz();
    }
}

Upvotes: 1

McDowell
McDowell

Reputation: 108959

Unfortunately, I do not have an answer for you, but I will say this...

Getting the objects to inject themselves looks like it might work - you needn't necessarily use a superclass:

public final class Foo {

  @Inject
  private BazService bazService;
  private Baz baz;

  @PostConstruct
  public void init() {
    InjectorFinder.getInjector().injectMembers(this);
    baz = bazService.loadBaz();
  }

  public void setBazService(BazService bazService) {
    this.bazService = bazService;
  }

}

I also see no reason to keep a reference to the injector, so consider a utility class:

public class InjectorFinder {
  public static Injector getInjector() {
    FacesContext facesContext = FacesContext
        .getCurrentInstance();
    ExternalContext extContext = facesContext
        .getExternalContext();
    Map<String, Object> applicationMap = extContext
        .getApplicationMap();
    return (Injector) applicationMap.get(Injector.class
        .getName());
  }
}

Does anything happen with @PostConstruct and serialization? It is something I haven't thought much about, but it may affect session beans.


This does not look like a sound technique. If I read the code right, dependencies will be injected every time the object is resolved.


I suspect this patch suffers from the problems I've mentioned (different resolver, same author, anyway). Bugs aside, trying to use two different implementations of JSF (Sun and Apache) at the same time is not going to work.


I have seen a couple of Guice/JSF projects in the wild (guicesf; jsf-sugar; maybe there are more?) but have not tried them, so I have no idea if they will help you or even how stable they are.

Whatever you do, it might be an idea to keep an eye on Web Beans (overview here) as this is likely to affect future bean handling features in JSF (if I understand Guice's place in the stack correctly, you could use it to implement Web Beans - not that I am recommending you do).

Upvotes: 1

Related Questions