Guice提供了一种绑定到提供者的方法:
bind(A.class).toProvider(AProvider.class);
虽然如果我的提供者需要抛出异常,那么CheckedProvider似乎是一个正确的基础接口:
public interface ConfigCheckedProvider<T> extends CheckedProvider<T> {
T get() throws ConfigException;
}
public AProvider implements ConfigCheckedProvider<A> { ... }
但是现在我的一些类需要注入A的实例。这我无法改变。但看起来像Provider方法不接受CheckedProvider类型。
如何使用基于CheckedProvider的提供商注入实例而不是提供商?
答案 0 :(得分:5)
根据您的要求,我将发表评论作为答案。
如果您有课程T
和已检查的提供者TProvider extends CheckedProvider<T>
,则无法仅注入T
:
@Inject
SomeClass(T t) { // Won't work
...
}
如果您使用普通Provider<T>
,就可以。这是故意做的。当创建对象可能因特定类型的异常而失败时,需要经过检查的提供程序,并且此失败必须由用户代码处理。普通提供商没有这样的功能。
Provider<T>
不允许从get()
方法中抛出已检查的异常,并且它抛出的任何未经检查的异常都可能被包装到ProvisionException
中,因此您无法可靠地捕获异常。此外,如果您直接注入T
并且提供程序的get()
方法失败,那么在注入期间您将收到错误,这可能会导致难以理解的堆栈跟踪(特别是如果您不使用Injector
直接)甚至他们的缺席。
经过检查的提供程序允许您从提供程序中抛出预先声明的异常类型,并且保证将这些异常原样传递给在已检查的提供程序上调用get()
的代码。通过这种方式,您可以可靠地捕获它们,但作为回报,您将失去注入由提供程序直接创建的对象的能力。
请参阅关于投掷和检查提供商的this manual,了解我刚才所写的更多背景信息。
答案 1 :(得分:0)
很明显,我所要求的是故意不提供的。但是,可以编写自己的已检查提供程序,该提供程序将实现Provider,因此可用于toProvider绑定。
例如,我提供了以下Checked Provider可能有意义:
public abstract class MyCheckedProvider<T, E extends Exception>
implements Provider<T> {
public abstract T getChecked() throws E;
@Override
public T get() {
try {
return getChecked();
} catch (Exception e) {
throw new ProvisionException("Checked provider threw exception", e );
}
}
}
使用此MyProvider,AProvider可能如下所示:
public class AProvider extends MyCheckedProvider<A, ConfigException> {
@Override
public A getChecked() throws ConfigException {
...
}
}
bind(A.class).toProvider(AProvider.class);
只有在提供程序出现问题时才要抛出ProvisionExceptions,所有这些都有效。对于其他逻辑,MyProvider显然应该有get方法的其他实现......