Search code examples
javaspringdependency-injectionguiceinject

Guice DI binding without adding Guice annotations


I have a usecase where I am using an external jar that is based on Spring, while my code is on Google guice.

I am trying to inject dependencies in this class of my dependency jar, by writing modules.

External class:

public class PTRS {
    @Inject
    private Event countEvent;
    @Inject
    private Event durationEvent;
    private GeoServiceClient gClient;
    public void setGeoServiceClient(GeoServiceClient client){this.gClient=client}

}

I am able to set the members with setters in @provides method in my module, but the @inject members have null, and I am getting a NullPointerException for countEvent and durationEvent.

My code uses following provider class to create an object to bind with PTRS class.

@Provides
PTRS new PTRS(Client client){
PTRS ptrs = new PTRS();
ptrs.setGeoServiceClient(client);
return ptrs;
}

How can I inject both these dependencies without changing the external class?


Solution

  • Inject a MembersInjector to populate @Inject-annotated fields (and call @Inject-annotated methods) on an object Guice doesn't create. Guice calls this "On-demand injection" in the wiki, though I haven't heard the term elsewhere.

    @Provides
    PTRS newPTRS(Client client, MembersInjector<PTRS> ptrsInjector){
      PTRS ptrs = new PTRS();
      ptrsInjector.injectMembers(ptrs);    // <-- inject members here
      ptrs.setGeoServiceClient(client);
      return ptrs;
    }
    

    If you have access to an Injector, which is itself injectable, you can call injectMembers(Class) directly, or call getMembersInjector to get a MembersInjector instance of the type of your choice. However, the best practice here is to inject as narrow of an interface as possible, for clarity of reading and ease of mocking.