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.

Reply via email to