How do I make Guice bind this generic correctly?
我正在开发一个处理消息的平台,但我遇到了 Guice 绑定的问题。我编写了一个示例项目来显示我遇到的问题,这是一个如下所示的异常:
代码来了。
接口
1 2 3 4 5 6 7 8 9 10 11 | public interface Middleware { void configure(); } public interface PreprocessorMiddleware<MessageType> extends Middleware { void prework(Context<MessageType> contextObj); } public interface PostprocessorMiddleware<MessageType> extends Middleware { void postwork(Context<MessageType> contextObj); } |
古斯绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | public class MiddlewareModule<MessageType> extends AbstractModule { private final List<Class<? extends PostprocessorMiddleware<MessageType>>> _postprocessors; private final List<Class<? extends PreprocessorMiddleware<MessageType>>> _preprocessors; public MiddlewareModule( List<Class<? extends PreprocessorMiddleware<MessageType>>> preprocessors, List<Class<? extends PostprocessorMiddleware<MessageType>>> postprocessors ) { _preprocessors = preprocessors; _postprocessors = postprocessors; } @Override protected void configure() { bindAllMiddleware(_preprocessors, new TypeLiteral<PreprocessorMiddleware<MessageType>>() {}); bindAllMiddleware(_postprocessors, new TypeLiteral<PostprocessorMiddleware<MessageType>>() {}); } private <T extends Middleware> void bindAllMiddleware(List<Class<? extends T>> middleware, TypeLiteral< T > type) { Multibinder< T > multibinder = Multibinder.newSetBinder(binder(), type); middleware.forEach(middlewareType -> bindMiddleware(multibinder, middlewareType)); } private <T extends Middleware> void bindMiddleware(Multibinder< T > binder, Class<? extends T> type) { binder().bind(type).in(Singleton.class); binder.addBinding().to(type); } } |
主要方法
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class Main { public static void main(String[] args) { List<Class<? extends PreprocessorMiddleware<Message>>> preprocessorMiddlewares = new ArrayList<>(); List<Class<? extends PostprocessorMiddleware<Message>>> postprocessorMiddlewares = new ArrayList<>(); preprocessorMiddlewares.add(ArbitraryPrepreprocessorMiddleware.class); postprocessorMiddlewares.add(ArbitraryPostprocessorMiddleware.class); MiddlewareModule<Message> module = new MiddlewareModule<>(preprocessorMiddlewares, postprocessorMiddlewares); Injector injector = Guice.createInjector(module); } } |
我做错了什么?
正如 jacobm 所描述的,您需要解决泛型问题,并且可能需要传入您要绑定的类型。幸运的是,您可以使用 Guice 的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | public class MiddlewareModule<MessageType> extends AbstractModule { private final Class<MessageType> _clazz; private final List<Class<? extends PostprocessorMiddleware<MessageType>>> _postprocessors; private final List<Class<? extends PreprocessorMiddleware<MessageType>>> _preprocessors; public MiddlewareModule( // Accept the message type in a way that survives erasure. Class<MessageType> clazz, List<Class<? extends PreprocessorMiddleware<MessageType>>> preprocessors, List<Class<? extends PostprocessorMiddleware<MessageType>>> postprocessors ) { _clazz = clazz; _preprocessors = preprocessors; _postprocessors = postprocessors; } @Override protected void configure() { // Use the Class to create your fully-specified TypeLiteral. bindAllMiddleware(_preprocessors, Types.newParameterizedType(PreprocessorMiddleware.class, _clazz)); bindAllMiddleware(_postprocessors, Types.newParameterizedType(PostprocessorMiddleware.class, _clazz)); } private <T extends Middleware> void bindAllMiddleware(List<Class<? extends T>> middleware, TypeLiteral< T > type) { Multibinder< T > multibinder = Multibinder.newSetBinder(binder(), type); middleware.forEach(middlewareType -> bindMiddleware(multibinder, middlewareType)); } private <T extends Middleware> void bindMiddleware(Multibinder< T > binder, Class<? extends T> type) { bind(type).in(Singleton.class); // Don't call binder() explicitly. binder.addBinding().to(type); } } |
请注意,这是未经测试的代码,因为我没有完整的 SSCCE;您可能需要调整类型参数以使 Guice 相信您在泛型中使用通配符是安全的。
您不能在
这是一个类似情况的更复杂的答案。结果是,如果你真的需要避免在每个调用点都使用类型文字,你可以再抽象一点,但这会带来相当高的复杂性成本。