Обобщить пример ноги робота с помощью Multibinding
У меня есть этот пример использования, который очень похож на пример с роботизированными ногами в Guice, за исключением того, что я не знаю, сколько у меня "ног". Поэтому я не могу использовать аннотации, необходимые для примера с ножками робота.
Я ожидаю собрать все эти "ноги" в java.util.Set с расширением Guice's Multibindings.
Технически, в PrivateModule я хотел бы представить реализацию непосредственно как элемент набора, который будет предоставлен расширением Multibindings. Я просто не знаю, как это сделать.
Для справки и примера кода см. Пример с ножками робота здесь: http://code.google.com/p/google-guice/wiki/FrequentlyAskedQuestions
Вот мой точный вариант использования:
У меня есть следующее:
// 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 - это интерфейс, расширяющий модуль.
1 ответ
Похоже, что вам нужно будет перепрыгнуть через несколько обручей, чтобы получить привязки из частного модуля, чтобы они могли быть в мультисвязке инжектора верхнего уровня.
Это должно работать:
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);
}
}
Этот обходной путь необходим, потому что мультииндикация должна происходить на инжекторе верхнего уровня. Но привязки приватных модулей не видны для этого инжектора, поэтому вам нужно их выставить.