java - 使用 Guice 注入(inject)通用接口(interface)子类型的实现

标签 java generics dependency-injection guice

我定义了以下 API:

public interface Input<I> {
    Collection<? extends I> read();
}

public interface Transformer<O, I> {
    Collection<? extends O> transform(Collection<? extends I> inputData);
}

public interface Output<O> {
    void write(Collection<? extends O> output);
}

public interface Executor {
    void execute();
}

以及以下实现:

public final class InputImpl implements Input<String> {
    @Override
    public Collection<? extends String> read() {
        return asList("1", "2");
    }
}

public final class TransformerImpl implements Transformer<Integer, String> {
    @Override
    public Collection<? extends Integer> transform(final Collection<? extends String> inputData) {
        return inputData.stream().map(Integer::parseInt).collect(Collectors.toList());
    }
}

public final class OutputImpl implements Output<Integer> {
    @Override
    public void write(final Collection<? extends Integer> output) {
        System.out.println(output);
    }
}

public final class ExecutorImpl<I, O> implements Executor {
    private final Input<I> input;
    private final Transformer<O, I> transformer;
    private final Output<O> output;

    @Inject
    public ExecutorImpl(final Input<I> input, final Transformer<O, I> transformer, final Output<O> output) {
        this.input = input;
        this.transformer = transformer;
        this.output = output;
    }

    public void execute() {
        final Collection<? extends I> inputData = input.read();
        final Collection<? extends O> outputData = transformer.transform(inputData);
        output.write(outputData);
    }
}

这是我尝试将 API 绑定(bind)到上面的实现:

public final class ModuleImpl extends AbstractModule {
    @Override
    protected void configure() {
        bind(new TypeLiteral<Input<String>>() {
        }).to(InputImpl.class);

        bind(new TypeLiteral<Transformer<Integer, String>>() {
        }).to(TransformerImpl.class);

        bind(new TypeLiteral<Output<Integer>>() {
        }).to(OutputImpl.class);

        bind(Executor.class).to(ExecutorImpl.class);
    }
}

当我尝试使用 Guice 注入(inject)器获取 Executor 的实例时,出现以下错误:

1) com.csc.playground.guice.api.Input<I> cannot be used as a key; It is not fully specified.
  at com.csc.playground.guice.ExecutorImpl.<init>(ExecutorImpl.java:25)
  at com.csc.playground.guice.module.ModuleImpl.configure(ModuleImpl.java:33)

2) com.csc.playground.guice.api.Transformer<O, I> cannot be used as a key; It is not fully specified.
  at com.csc.playground.guice.ExecutorImpl.<init>(ExecutorImpl.java:25)
  at com.csc.playground.guice.module.ModuleImpl.configure(ModuleImpl.java:33)

3) com.csc.playground.guice.api.Output<O> cannot be used as a key; It is not fully specified.
  at com.csc.playground.guice.ExecutorImpl.<init>(ExecutorImpl.java:25)
  at com.csc.playground.guice.module.ModuleImpl.configure(ModuleImpl.java:33)

最佳答案

从概念上讲,问题出在这里:

@Inject
public ExecutorImpl(final Input<I> input,
        final Transformer<O, I> transformer,
        final Output<O> output) {

当 guice 尝试实现依赖关系时,例如 Input<I> ,它不知道它是什么类型;这就是“未完全指定”的意思。

您可以通过指定通用类型来解决这个问题。您执行此操作的方式与您在 AbstractModule 中执行绑定(bind)的方式相同,例如,而不是绑定(bind)到 ExecutorImpl.class , 做:

bind(Executor.class).to(new TypeLiteral<ExecutorImpl<String, Integer>>() {});

关于java - 使用 Guice 注入(inject)通用接口(interface)子类型的实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23806429/

相关文章:

java - 关于泛型和注释的一些好的 Java 面试问题和答案是什么?

java - 构造函数注入(inject)与字段注入(inject)

C# Asp.net core 使用 RestSharp 进行依赖注入(inject)

javascript - 使用自定义文本自动链接到代码

java - 日历无法获取非英语语言的日期名称

ios - 使用内部列表对列表进行分类

javascript - 将依赖项指定为字符串是否会使 AngularJS 中的 DI 更快?

java - Java中的多维ArrayList

java - INNER JOIN 在 hibernate 状态下不起作用?

arrays - 当所有类型都正确定义时,为什么 Swift 的 reduce 函数会抛出 'Type of expression ambigious without more context' 错误?