[英]How do I bind the Interface with Implementation for Generic Classes?
[Guice 4.0]
我想为通用类提供一个接口,并在使用Guice进行依赖项注入中使用它。 对于下面列出的代码,我得到以下错误:
Exception in thread "main" com.google.inject.CreationException: Unable to create injector, see the following errors:
1) Could not find a suitable constructor in com.ulmon.fsqtransit.guicetest.Class1. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.
at com.ulmon.fsqtransit.guicetest.Class1.class(Class1.java:14)
at com.ulmon.fsqtransit.guicetest.Module.configure(Module.java:14)
-
public class Class1<T1 extends Number, T2 extends Number>
implements InterfClass1<T1, T2> {
public static final String ANNOT1 = "ANNOT1";
public static final String ANNOT2 = "ANNOT2";
private T1 t1;
private T2 t2;
// for the factory
@AssistedInject
public Class1(
@Assisted(Class1.ANNOT1) T1 t1,
@Assisted(Class1.ANNOT2) T2 t2
) {
this.t1 = t1;
this.t2 = t2;
}
public T1 getT1() {
return t1;
}
public T2 getT2() {
return t2;
}
}
public class Module extends AbstractModule {
@Override
protected void configure() {
bind(new TypeLiteral<InterfClass1<Integer, Integer>>(){})
.to(new TypeLiteral<Class1<Integer, Integer>>(){});
}
public static void main(String[] args) {
Injector inj = Guice.createInjector(new Module());
}
}
是什么导致此错误?
让我们添加工厂并修改模块(从模块中删除InterfClass1接口):
public interface Class1Factory<T1 extends Number, T2 extends Number> {
public Class1<T1, T2> createClass1(
@Assisted(Class1.ANNOT1) T1 t1,
@Assisted(Class1.ANNOT2) T2 t2
);
}
public class Module extends AbstractModule {
@Override
protected void configure() {
install(new FactoryModuleBuilder()
.build(new TypeLiteral<Class1Factory<Integer, Double>>(){}));
}
public static void main(String[] args) {
Injector inj = Guice.createInjector(new Module());
Class1Factory f = inj.getInstance(Key.get(new TypeLiteral<Class1Factory<Integer, Double>>(){}));
f.createClass1(10, 11.0);
}
}
它很好用!
现在让我们合并接口:
public class Module extends AbstractModule {
@Override
protected void configure() {
bind(new TypeLiteral<InterfClass1<Integer, Double>>(){})
.to(new TypeLiteral<Class1<Integer, Double>>(){});
install(new FactoryModuleBuilder()
.build(new TypeLiteral<Class1Factory<Integer, Double>>(){}));
}
public static void main(String[] args) {
Injector inj = Guice.createInjector(new Module());
Class1Factory f = inj.getInstance(Key.get(new TypeLiteral<Class1Factory<Integer, Double>>(){}));
f.createClass1(10, 11.0);
}
}
我们得到:
1) Could not find a suitable constructor in com.ulmon.fsqtransit.guicetest.Class1. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.
at com.ulmon.fsqtransit.guicetest.Class1.class(Class1.java:15)
at com.ulmon.fsqtransit.guicetest.Module.configure(Module.java:14)
好吧,让我们不管错误如何,都更改工厂:
public interface Class1Factory<T1 extends Number, T2 extends Number> {
public InterfClass1<T1, T2> createClass1(
@Assisted(Class1.ANNOT1) T1 t1,
@Assisted(Class1.ANNOT2) T2 t2
);
}
我们得到:
1) Could not find a suitable constructor in com.ulmon.fsqtransit.guicetest.Class1. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.
at com.ulmon.fsqtransit.guicetest.Class1.class(Class1.java:15)
at com.ulmon.fsqtransit.guicetest.Module.configure(Module.java:14)
2) com.ulmon.fsqtransit.guicetest.InterfClass1<java.lang.Integer, java.lang.Double> is an interface, not a concrete class. Unable to create AssistedInject factory.
while locating com.ulmon.fsqtransit.guicetest.InterfClass1<java.lang.Integer, java.lang.Double>
at com.ulmon.fsqtransit.guicetest.Class1Factory.createClass1(Class1Factory.java:1)
但是,如果删除模块中接口和类之间的关系,并将此关系添加到工厂的规范中,则不会出错:
public class Module extends AbstractModule {
@Override
protected void configure() {
install(new FactoryModuleBuilder()
.implement(new TypeLiteral<InterfClass1<Integer, Double>>(){}
, new TypeLiteral<Class1<Integer, Double>>(){})
.build(new TypeLiteral<Class1Factory<Integer, Double>>(){}));
}
public static void main(String[] args) {
Injector inj = Guice.createInjector(new Module());
Class1Factory f = inj.getInstance(Key.get(new TypeLiteral<Class1Factory<Integer, Double>>(){}));
f.createClass1(10, 11.0);
}
}
工作正常!
为什么Guice有这种奇怪的行为? 为什么无论工厂如何,我都无法将接口与实现类相关联?
我无法弄清楚您要做什么,但是在我看来,您实际上并不是在尝试创建AssistedInject工厂,因为您尚未创建工厂接口。 在这种情况下,您根本不需要使用@Assisted
参数。 您的构造函数应如下所示(该类没有其他更改):
@Inject
public Class1(
@Named(Class1.ANNOT1) T1 t1,
@Named(Class1.ANNOT2) T2 t2
) {
然后,在模块中指定绑定。 您必须明确地告诉Guice要为参数以及指定的注释注入什么:
@Override
protected void configure() {
bind(new TypeLiteral<InterfClass1<Integer, Integer>>(){})
.to(new TypeLiteral<Class1<Integer, Integer>>(){});
bind(Integer.class)
.annotatedWith(Names.named(Class1.ANNOT1))
.toInstance(5);
bind(Integer.class)
.annotatedWith(Names.named(Class1.ANNOT2))
.toInstance(15);
}
然后,我们可以这样运行它:
public static void main(String[] args) {
Injector inj = Guice.createInjector(new Module());
InterfClass1<Integer, Integer> interf =
inj.getInstance(Key.get(new TypeLiteral<InterfClass1<Integer, Integer>>(){}));
System.out.println(interf.getClass());
System.out.println("T1: " + interf.getT1() + " T2: " + interf.getT2());
}
如您所见,在运行它时,它将注入Class
实现,并带有指定的两个参数:
class guice.Class1
T1: 5 T2: 15
如果你正在试图建立一个工厂的Class1
对象,使用AssistedInject,这是因为你所指定的generit类型参数的方式显著更加困难。 不幸的是,您不能以常规方式使用AssistedInject注入泛型工厂 ,并且这变得更加困难,因为您的Class1
实现需要T1 extends Number
,但是您的接口可以是您想要的任何T1
。 这意味着您的工厂必须将接收到的输入参数的类型限制为Number
子类; 换句话说,您的工厂不能只创建它想要的任何InterfClass1
,它只能创建具有适当输入参数的实例。
希望答案的前半部分是您要执行的操作。 如果不是,我们需要有关您的用例的更多信息,以便能够回答此问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.