Revision: 1262
Author: sberlin
Date: Tue Sep 21 11:50:45 2010
Log: Edited wiki page ExtensionSPI through web user interface.
http://code.google.com/p/google-guice/source/detail?r=1262
Modified:
/wiki/ExtensionSPI.wiki
=======================================
--- /wiki/ExtensionSPI.wiki Wed Aug 19 13:57:36 2009
+++ /wiki/ExtensionSPI.wiki Tue Sep 21 11:50:45 2010
@@ -1,69 +1,50 @@
-#summary Interaction between Guice Extensions
-#labels Guice21
+#summary Interaction between Guice SPI & Extensions
+#labels Guice30
=Extensions SPI=
-Last year we expanded our SPI to expose rich details about modules and
injectors. The elements API can inspect, extend and even rewrite Guice
configuration. It's an essential tool used by GIN, Modules.override(),
Grapher, Guiceberry's controllable injection, and others. Unfortunately,
SPI coverage is currently limited to the Guice core. Programmatic
inspection of Multibindings, Assisted Inject, Servlets and even provider
methods aren't exposed via the SPI. It's time to address this!
-
-I'm rolling around two proposals as to how extensions will work in the SPI
and I'm looking for feedback. I've got a code example to illustrate each
approach. For each, the code prints all of an injector's bindings,
including deluxe formatting for Assisted Inject. Once implemented, the full
extensions SPI will be used to expose information for many Guice extensions.
-
-==A) client instanceof==
-
+In Guice 2.0 we expanded our SPI to expose rich details about modules and
injectors. The elements API can inspect, extend and even rewrite Guice
configuration. It's an essential tool used by GIN, Modules.override(),
Grapher, Guiceberry's controllable injection, and others. In Guice 3.0 we
expanded the SPI to include extensions! Extensions such as Multibinder,
Assisted Inject, Servlets and others can expose their details through
programmatic inspection.
+
+==How Extensions Participate==
+An extension author needs to do two things. First it must create a
subinterface of BindingTargetVisitor that is specific to its extension.
For example, the servlet extension has ServletModuleTargetVisitor, and the
Multibinder extension has MultibindingsTargetVisitor. The extension must
also bind the extension's provider instance to a
ProviderWithExtensionVisitor. The implementation of acceptExtensionVisitor
must do an instanceof check on the BindingTargetVisitor and call the
appropriate visit method. If the visitor is an instance of the extension's
visitor, it must visit the appropriate extension method, otherwise it must
visit the normal ProviderInstanceBinding.
+For example, this is what MapBinder & Multibinder do:
{{{
- public static void main(String[] args) {
- Injector injector = Guice.createInjector(...);
-
- for (Binding<?> binding : injector.getBindings().values()) {
- System.out.println(binding.acceptTargetVisitor(new
DefaultBindingTargetVisitor<Object, String>() {
-
- public String visit(ProviderInstanceBinding<?> binding) {
- Provider<?> provider = binding.getProviderInstance();
- if (provider instanceof FactoryProvider) {
- FactoryProvider factoryProvider = (FactoryProvider) provider;
- return "Factory: " + binding.getKey()
- + " builds " + factoryProvider.getImplementationType()
- + " using parameters " +
factoryProvider.getAssistedParameters();
- }
-
- return super.visit(binding);
- }
-
- protected String visitOther(Binding<?> binding) {
- return binding.toString();
- }
- }));
- }
+ public <R, B> R acceptExtensionVisitor(BindingTargetVisitor<B, R>
visitor,
+ ProviderInstanceBinding<? extends B> binding) {
+ if (visitor instanceof MultibindingsTargetVisitor) {
+ return ((MultibindingsTargetVisitor<Map<K, V>,
R>)visitor).visit(this);
+ } else {
+ return visitor.visit(binding);
+ }
}
}}}
-The user implements the standard visit(ProviderInstanceBinding) method.
They're responsible for knowing what kind of binding(s) Assisted Inject
creates behind-the-scenes, and for doing an instanceof on the bound
provider. They implement only the BindingTargetVisitor interface.
-
-The extension author needs to document which bindings to look for, and
what instanceof call the user should perform.
-
-==B) visitor subtypes==
+==How Users Participate==
+To visit an extension's custom methods, users must implement the
extension's custom visitor interface and call
binding.acceptTargetVisitor(myVisitor). For example:
{{{
public static void main(String[] args) {
Injector injector = Guice.createInjector(new PorscheModule());
for (Binding<?> binding : injector.getBindings().values()) {
- System.out.println(binding.acceptTargetVisitor(new
AssistedVisitor()));
+ System.out.println(binding.acceptTargetVisitor(new
MultibindVisitor()));
}
}
- static class AssistedVisitor extends DefaultBindingTargetVisitor<Object,
String>
- implements AssistedBindingVisitor<Object, String> {
- public String visit(FactoryProvider<Object> factoryProvider,
ProviderInstanceBinding<?> binding) {
- return "Factory: " + binding.getKey()
- + " builds " + factoryProvider.getImplementationType()
- + " using parameters " + factoryProvider.getAssistedParameters();
+ static class MultibindVisitor extends DefaultBindingTargetVisitor<?,
String>
+ implements MultibindingsTargetVisitor<?, String> {
+ public String visit(MultibinderBinding<?> multibinder) {
+ return "Key: " + multibinder.getSetKey()
+ + " uses bindings: " + multibinder.getElements()
+ + " permitsDuplicates: " + multibinder.permitsDuplicates();
+ }
+ public String visit(MapBinderBinding<?> mapbinder) {
+ return "Key: " + mapbinder.getMapKey()
+ + " uses entries: " + mapbinder.getEntries()
+ + " permitsDuplicates: " + mapbinder.permitsDuplicates();
}
protected String visitOther(Binding<?> binding) {
return binding.toString();
}
}
}}}
-
-The user implements a special interface for each extension that they're
interested in. It adds a new visit() method that's specific to the
extension. Because they must implement both the extension-interface and the
standard BindingTargetVisitor interface, this approach can't easily be used
with anonymous inner classes.
-
-The extension author needs to write a special interface for their visit
method. The Guice core needs to expose hooks for extensions to discover
their specific visitor types, and the extension author must use these hooks.
--
You received this message because you are subscribed to the Google Groups
"google-guice-dev" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-guice-dev?hl=en.