Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to move an anonymous Provider that references fields in the module into a separate class?

Toy example:

public class MyModule extends AbstractModule {
  private static final Foo foo;

  public MyModule(Foo foo) {
    this.foo = foo;
  }

  @Override
  public void configure() {
    bind(Bar.class).toProvider(new Provider<Bar>() {
      @Override public Bar get() {
        return foo.getBar();
      }
    });
  }
}

This lets me lazily invoke the .getBar() method of a user-provided Foo instance stored in a field of MyModule. However now the provider has its own dependencies - hence I need to define a non-anonymous class I specify an @Inject constructor on. Something like:

public class MyModule extends AbstractModule {
  private static final Foo foo;

  public MyModule(Foo foo) {
    this.foo = foo;
  }

  @Override
  public void configure() {
    bind(Bar.class).toProvider(BarProvider.class);
  }

  BarProvider implements Provider<Bar> {
    private Baz baz;

    @Inject BarProvider(Baz baz) {
      this.baz = baz;
    }

    @Override public Bar get() {
      return foo.getBar(baz);
    }
  }
}

Perfect! Except Guice doesn't like this...

Exception in thread "main" com.google.inject.CreationException: Unable to create injector, see the following errors:

1) Injecting into inner classes is not supported. Please use a 'static' class (top-level or nested) instead of com.example.MyModule$BarProvider.

So, I'm in a bind. I need to access both a field on the module and an injected type from a Provider class at the same time. Is there any way to do this?


Note: this toy example excludes some of the actual complexity - in particular the bind() statement is more involved, which is why I can't simply define an @Provides method.

like image 204
dimo414 Avatar asked Jan 20 '26 18:01

dimo414


1 Answers

In part, injecting into an inner class is impossible because Guice can't reflectively create an inner instance without an outer parent instance (the equivalent of the arcane outerInstance.new InnerInstance() syntax).

Some options:

  • Make Foo injectable through your graph, possibly hidden in a PrivateModule so it's not exposed to your entire graph (if that's important to you).
  • Use an anonymous inner Provider (or an extracted equivalent), and get a Provider<Baz> from AbstractModule's getProvider(Class<T>) method. You'll get an exception if you try to call that before the Injector is created, but for creating a Provider the way you're doing, that's probably not a problem.
  • Post your bind outside of a toy problem, to see whether @Provides is possible with some cleverness.

Related: Accessing Guice injector in its Module?

like image 59
Jeff Bowman Avatar answered Jan 22 '26 07:01

Jeff Bowman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!