简体   繁体   中英

Guice instance binding for generic type

I want my module to bind a child class of Parent to an instance that I create.

public class MyModule<T extends Parent> implements AbstractModule {
  T myAwesomeInstance;
  MyModule(String[] args, Class<T extends Parent> clazz) {
    myAwesomeInstance = clazz.newInstance(); // catching exceptions and stuff ...
    ArgumentParser.configure(myAwesomeInstance, args);
  }

  @Override
  void configure() {
      bind(new TypeLiteral<T>(){}).toInstance(myAwesomeInstance);
  }
}

This code compiles fine but when I try to run, Guice would complain "T cannot be used as a key; It is not fully specified". How do I bind a generic class to an instance of that class which my module create?

My solution is different from the suggested duplicate. I need to save the class object in order to correctly bind the class to the instance of my choice.

public class MyModule<T extends Parent> implements AbstractModule {
  T myAwesomeInstance;
  Class<T> _clazz;

  MyModule(String[] args, Class<T extends Parent> clazz) {
    myAwesomeInstance = clazz.newInstance(); // catching exceptions and stuff ...
    _clazz = clazz;
    ArgumentParser.configure(myAwesomeInstance, args);
  }

  @Override
  void configure() {
      bind(TypeLiteral.get(_clazz)).toInstance(myAwesomeInstance);
  }
}

No need to use TypeLiteral , you can just use Key directly. (And that gives you an opportunity to add an annotation if you want.)

It's probably better to defer constructing instances until singleton time, instead of when the module is instantiated. For example, you could do:

public final class MyModule<T extends Parent> extends AbstractModule {
  private final Key<T> key;
  private final Provider<T> provider;

  public MyModule(final Class<T> clazz, final String[] args) {
    this.key = Key.get(clazz); // Or add an annotation if you feel like it
    this.provider = new Provider<T>() {
      @Override public T get() {
        try {
          T instance = clazz.newInstance();
          // etc.
        } catch (ReflectiveOperationException ex) {
          // throw a RuntimeException here
        }
      }
    };
  }

  @Override protected void configure() {
    bind(key).toProvider(provider).in(Singleton.class);
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM