如何将引用模块中字段的匿名 Provider 移动到单独的 class?
How to move an anonymous Provider that references fields in the module into a separate class?
玩具示例:
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();
}
});
}
}
这让我可以懒惰地调用存储在 MyModule
字段中的用户提供的 Foo
实例的 .getBar()
方法。但是现在 provider has its own dependencies - 因此我需要定义一个非匿名的 class 我指定了一个 @Inject
构造函数。类似于:
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);
}
}
}
完美!除了 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.
所以,我进退两难了。我需要同时访问模块上的字段和来自 Provider
class 的注入类型。有什么办法吗?
注意: 这个玩具示例排除了一些实际的复杂性 - 特别是 bind()
语句涉及更多,这就是为什么我不能简单地定义一个@Provides
方法。
在某种程度上,注入内部 class 是不可能的,因为 Guice 无法在没有外部父实例的情况下反射性地创建内部实例(相当于神秘的 outerInstance.new InnerInstance()
语法)。
部分选项:
- 使 Foo 可通过您的图表注入,可能隐藏在 PrivateModule 中,因此它不会暴露在您的整个图表中(如果这对您很重要)。
- 使用匿名内部提供者(或提取的等效项),并从 AbstractModule 的
getProvider(Class<T>)
方法中获取 Provider<Baz>
。如果您尝试在创建 Injector 之前调用它,您将得到一个异常,但对于按照您正在做的方式创建 Provider,这可能不是问题。
- Post 你的
bind
不是玩具问题,看看 @Provides
是否可以用一些聪明的方法。
相关:Accessing Guice injector in its Module?
我意识到让 Guice 为我构建我的 Provider
我已经挂了,我实际上不需要这样做。尽管 Guice 的文档中的示例传递了一个 DatabaseTransactionLogProvider.class
与第一个片段更好的平行是手动构建我的 Provider
的实例,并传递 Foo
实例和 Provider<Baz>
实例 (provided by the module).
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 BarProvider(foo, getProvider(Baz.class));
}
static BarProvider implements Provider<Bar> {
private final Foo foo;
private final Provider<Baz> bazProvider;
BarProvider(Foo foo, Provider<Baz> bazProvider) {
this.foo = foo;
this.bazProvider = bazProvider;
}
@Override public Bar get() {
return foo.getBar(bazProvider.get());
}
}
}
玩具示例:
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();
}
});
}
}
这让我可以懒惰地调用存储在 MyModule
字段中的用户提供的 Foo
实例的 .getBar()
方法。但是现在 provider has its own dependencies - 因此我需要定义一个非匿名的 class 我指定了一个 @Inject
构造函数。类似于:
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);
}
}
}
完美!除了 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.
所以,我进退两难了。我需要同时访问模块上的字段和来自 Provider
class 的注入类型。有什么办法吗?
注意: 这个玩具示例排除了一些实际的复杂性 - 特别是 bind()
语句涉及更多,这就是为什么我不能简单地定义一个@Provides
方法。
在某种程度上,注入内部 class 是不可能的,因为 Guice 无法在没有外部父实例的情况下反射性地创建内部实例(相当于神秘的 outerInstance.new InnerInstance()
语法)。
部分选项:
- 使 Foo 可通过您的图表注入,可能隐藏在 PrivateModule 中,因此它不会暴露在您的整个图表中(如果这对您很重要)。
- 使用匿名内部提供者(或提取的等效项),并从 AbstractModule 的
getProvider(Class<T>)
方法中获取Provider<Baz>
。如果您尝试在创建 Injector 之前调用它,您将得到一个异常,但对于按照您正在做的方式创建 Provider,这可能不是问题。 - Post 你的
bind
不是玩具问题,看看@Provides
是否可以用一些聪明的方法。
相关:Accessing Guice injector in its Module?
我意识到让 Guice 为我构建我的 Provider
我已经挂了,我实际上不需要这样做。尽管 Guice 的文档中的示例传递了一个 DatabaseTransactionLogProvider.class
与第一个片段更好的平行是手动构建我的 Provider
的实例,并传递 Foo
实例和 Provider<Baz>
实例 (provided by the module).
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 BarProvider(foo, getProvider(Baz.class));
}
static BarProvider implements Provider<Bar> {
private final Foo foo;
private final Provider<Baz> bazProvider;
BarProvider(Foo foo, Provider<Baz> bazProvider) {
this.foo = foo;
this.bazProvider = bazProvider;
}
@Override public Bar get() {
return foo.getBar(bazProvider.get());
}
}
}