2011-07-08 21 views
6

我有这个用例非常类似于Guice的机器人腿的例子,除了我不知道我有多少“腿”。因此我不能使用机器人腿示例所需的注释。概括guice的机器人腿与多重绑定的例子

我期望将所有这些“腿”收集在一个java.util.Set中,并带有Guice的Multibindings扩展。

从技术上讲,在一个PrivateModule中,我想直接将一个实现公开为Multibindings扩展提供的一组元素。我只是不知道该怎么做。

参考,代码示例,请参阅机器人腿例子在这里:http://code.google.com/p/google-guice/wiki/FrequentlyAskedQuestions#How_do_I_build_two_similar_but_slightly_different_trees_of_objec


这里是我的精确用例:

我有以下几点:

// Main application 
public interface MyTree {...} 
public interface MyInterface { 
    public MyTree getMyTree() {} 
} 
public abstract class MyModule extends PrivateModule {} 
public class MyManager { 
    @Inject MyManager (Set<MyInterface> interfaces){ this.interfaces = interfaces } 
} 
public class MainModule extends AbstractModule { 
    public void configure() { 
    // Install all MyModules using java.util.ServiceLoader. 
    } 
} 


// In expansion "square.jar" 
public class SquareTree implements MyTree {...} 
public class SquareImplementation implements MyInterface { 
    @Inject SquareImplementation (MyTree tree) { this.tree = tree; } 
    public MyTree getMyTree() { return this.tree; } 
} 
public class SquareModule extends MyModule { // correctly defined as a ServiceLoader's service. 
    public void configure() { 
    // How to make this public IN a multibinder's set? 
    bind(MyInterface.class).to(SquareImplementation.class); 

    // Implementation specific to the Squareimplementation. 
    bind(MyTree.class).to(SquareTree.class); 
    } 
} 

// In expansion "circle.jar" 
public class CircleTree implements MyTree {...} 
public class CircleImplementation implements MyInterface { 
    @Inject CircleImplementation (MyTree tree) { this.tree = tree; } 
    public MyTree getMyTree() { return this.tree; } 
} 
public class CircleModule extends MyModule { // correctly defined as a ServiceLoader's service. 
    public void configure() { 
    // How to make this public IN a multibinder's set? 
    bind(MyInterface.class).to(CircleImplementation.class); 

    // Implementation specific to the Circle implementation. 
    bind(MyTree.class).to(CircleTree.class); 
    } 
} 

由于我在谈论扩展罐,起初我不认识它们,我甚至不知道它们中有多少个:我需要将MyModule加载到j.u.ServiceLoader,每个模块应该定义一个MyInterface实现(这两个部分都可以)。

问题是让所有的MyInterface实现在一个集合(在MyManager)。我怎样才能做到这一点?


解决方案,完全基于杰西的回答是:

// Create the set binder. 
Multibinder<MyInterface> interfaceBinder = Multibinder.newSetBinder(binder(), MyInterface.class, MyBinding.class); 

// Load each module that is defined as a service. 
for (final MyModule module : ServiceLoader.load(MyModule.class)) { 

    // Generate a key with a unique random name, so it doesn't interfere with other bindings. 
    final Key<MyInterface> myKey = Key.get(MyInterface.class, Names.named(UUID.randomUUID().toString())); 
    install(new PrivateModule() { 
    @Override protected void configure() { 
     // Install the module as part of a PrivateModule so they have full hands on their own implementation. 
     install(module); 
     // Bind the unique named key to the binding of MyInterface. 
     bind(myKey).to(MyInterface.class); 
     // Expose the unique named binding 
     expose(myKey); 
    } 
    }); 
    // bind the unique named binding to the set 
    interfaceBinder.addBinding().to(myKey); 
} 

这让我不强迫“顾客”来扩展PrivateModule,而是使用任何模块实现,如果MyModule的是扩展的接口模块。

回答

9

看起来您需要跳过一些环节来从私有模块中提示绑定,以便它们可以位于顶层注入器的多重绑定中。

这应该工作:

public class SquareModule extends AbstractModule { // does not extend PrivateModule 
    @Overide public void configure() { 
    // this key is unique; each module needs its own! 
    final Key<MyInterface> keyToExpose 
     = Key.get(MyInterface.class, Names.named("square")); 

    install(new PrivateModule() { 
     @Override public void configure() { 

     // Your private bindings go here, including the binding for MyInterface. 
     // You can install other modules here as well! 
     ... 

     // expose the MyInterface binding with the unique key 
     bind(keyToExpose).to(MyInterface.class); 
     expose(keyToExpose); 
     } 
    }); 

    // add the exposed unique key to the multibinding 
    Multibinder.newSetBinder(binder(), MyInterface.class).addBinding().to(keyToExpose); 
    } 
} 

这个解决办法是必要的,因为multibindings需要在顶层注射器的情况发生。但私有模块绑定对于该注入器不可见,所以您需要公开它们。

+0

谢谢杰西,但是在阅读你的答案后,我不确定我是否正确地解释了这个问题。所以我用一个例子纠正了我的问题。现在这更容易理解吗? –

+0

好吧,我会测试你的新答案并在这里报告结果。 –

+0

是的,它完美的工作。使其变得可模块化是相当困难的,但没关系。 –