在 Guice 中注入通用工厂

2022-09-04 23:24:42

下面的代码是生成给定的 .工厂不在乎是什么:对于任何类型,它都可以从.Bar<T>Foo<T>TTBar<T>Foo<T>

import com.google.inject.*;
import com.google.inject.assistedinject.*;

class Foo<T> {
  public void flip(T x) { System.out.println("flip: " + x); }
}

interface Bar<T> {
  void flipflop(T x);
}

class BarImpl<T> implements Bar<T> {
  Foo<T> foo;

  @Inject
  BarImpl(Foo<T> foo) { this.foo = foo; }

  public void flipflop(T x) { foo.flip(x); System.out.println("flop: " + x); }
}

interface BarFactory {
  <T> Bar<T> create(Foo<T> f);
}

class Module extends AbstractModule {
  public void configure() {
    bind(BarFactory.class)
      .toProvider( 
          FactoryProvider.newFactory( BarFactory.class, BarImpl.class ) 
                   );
  }
}

public class GenericInject {
  public static void main(String[] args) {
    Injector injector = Guice.createInjector(new Module());

    Foo<Integer> foo = new Foo<Integer>();
    Bar<Integer> bar = injector.getInstance(BarFactory.class).create(foo);
    bar.flipflop(0);
  }
}

当我运行代码时,我从 Guice 收到以下错误:

1) No implementation for BarFactory was bound.
  at Module.configure(GenericInject.java:38)

2) Bar<T> cannot be used as a key; It is not fully specified.

我在 Guice 文档中找到的泛型的唯一参考是使用 .但是我没有文字类型,我有一个与工厂完全无关的通用占位符。有什么提示吗?TypeLiteral


答案 1

一种选择是手动编写BarFactory样板:

class BarImplFactory implements BarFactory {
  public <T> Bar<T> create(Foo<T> f) {
    return new BarImpl(f);
  }
}

绑定变为

bind(BarFactory.class).to(BarImplFactory.class);

答案 2

如果您将 guice 视为类似于 spring 的布线系统,那么连接一个通用实例就没有意义。您将特定实例连接到键,以便当另一个实例化类使用@Inject BarFactory 标记某些内容时,您将获得特定创建的实例。

由于您的实现是通用的,因此您没有提供足够的信息来注入特定实例。虽然我没有使用工厂供应商,但我的假设是你需要将Barfactory绑定到一个完全参数化的实例,例如 而不是 BarImpl )BarImpl<Concrete>

顺便说一句,由于您正在绑定BarFactory.class如果您想绑定多个实例,则必须以某种方式对其进行屈折,无论是按名称,还是像(尚未检查语法,但是)

bind(BarFactory.class).annotatedWith(Names.named("name1"))
      .toProvider( 

or by generics, bind(BarFactory<Concrete>).toProvider...

推荐