Javadoc for PrivateModules

git-svn-id: https://google-guice.googlecode.com/svn/trunk@634 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/extensions/privatemodules/src/com/google/inject/privatemodules/PrivateModule.java b/extensions/privatemodules/src/com/google/inject/privatemodules/PrivateModule.java
index f469e41..c3082bc 100644
--- a/extensions/privatemodules/src/com/google/inject/privatemodules/PrivateModule.java
+++ b/extensions/privatemodules/src/com/google/inject/privatemodules/PrivateModule.java
@@ -51,6 +51,40 @@
 import org.aopalliance.intercept.MethodInterceptor;
 
 /**
+ * A module whose configuration information is hidden from other modules. Only bindings that are
+ * explicitly {@link #expose(Class) exposed} will be available to other modules and to the injector.
+ * Exposed keys must be explicitly bound, either directly or via another module that's installed
+ * by the private module.
+ *
+ * <p>In addition to the bindings configured via {@link #configurePrivateBindings()}, bindings will
+ * be created for all methods with the {@literal @}{@link com.google.inject.Provides Provides}
+ * annotation. These bindings will be hidden from other modules unless the methods also have the
+ * {@literal @}{@link Exposed} annotation:
+ *
+ * <pre>
+ * public class FooBarBazModule extends PrivateModule {
+ *   protected void configurePrivateBindings() {
+ *     bind(Foo.class).to(RealFoo.class);
+ *     expose(Foo.class);
+ *
+ *     install(new TransactionalBarModule());
+ *     expose(Bar.class).annotatedWith(Transactional.class);
+ *
+ *     bind(SomeImplementationDetail.class);
+ *     install(new MoreImplementationDetailsModule());
+ *   }
+ *
+ *   {@literal @}Provides {@literal @}Exposed
+ *   public Baz provideBaz() {
+ *     return new SuperBaz();
+ *   }
+ * }
+ * </pre>
+ *
+ * <p>Private modules are implemented with {@link Injector#createChildInjector(Module[]) parent
+ * injectors.} Types that inject an {@link Injector} will be provided with the child injector. This
+ * injector includes private bindings that are not available from the parent injector.
+ *
  * @author jessewilson@google.com (Jesse Wilson)
  */
 public abstract class PrivateModule implements Module {
@@ -68,32 +102,31 @@
   private Binder privateBinder;
 
   public final synchronized void configure(Binder binder) {
-    // when exposes is null, we're being run for the public injector
+    // when 'exposes' is null, we're being run for the public injector
     if (exposes == null) {
       configurePublicBindings(binder);
+      return;
+    }
 
     // otherwise we're being run for the private injector
-    } else {
-      checkState(this.privateBinder == null, "Re-entry is not allowed.");
-      privateBinder = binder.skipSources(PrivateModule.class);
-      try {
-        configurePrivateBindings();
+    checkState(this.privateBinder == null, "Re-entry is not allowed.");
+    privateBinder = binder.skipSources(PrivateModule.class);
+    try {
+      configurePrivateBindings();
 
-        ProviderMethodsModule providerMethodsModule = ProviderMethodsModule.forPrivateModule(this);
-        for (ProviderMethod<?> providerMethod
-            : providerMethodsModule.getProviderMethods(privateBinder)) {
-          providerMethod.configure(privateBinder);
-          if (providerMethod.getMethod().isAnnotationPresent(Exposed.class)) {
-            expose(providerMethod.getKey());
-          }
+      ProviderMethodsModule providerMethods = ProviderMethodsModule.forPrivateModule(this);
+      for (ProviderMethod<?> providerMethod : providerMethods.getProviderMethods(privateBinder)) {
+        providerMethod.configure(privateBinder);
+        if (providerMethod.getMethod().isAnnotationPresent(Exposed.class)) {
+          expose(providerMethod.getKey());
         }
-
-        for (Expose<?> expose : exposes) {
-          expose.initPrivateProvider(binder);
-        }
-      } finally {
-        privateBinder = null;
       }
+
+      for (Expose<?> expose : exposes) {
+        expose.initPrivateProvider(binder);
+      }
+    } finally {
+      privateBinder = null;
     }
   }
 
@@ -131,15 +164,26 @@
     }
   }
 
+  /** Marker object used to indicate the private injector has been created */
   private static class Ready {}
 
-  public abstract void configurePrivateBindings();
+  /**
+   * Creates bindings and other configurations private to this module. Use {@link #expose(Class)
+   * expose()} to make the bindings in this module available externally.
+   */
+  protected abstract void configurePrivateBindings();
 
+  /** Makes the binding for {@code key} available to other modules and the injector. */
   protected final <T> void expose(Key<T> key) {
     checkState(exposes != null, "Cannot expose %s, private module is not ready");
     exposes.add(new Expose<T>(sourceProvider.get(), readyProvider, key));
   }
 
+  /**
+   * Makes a binding for {@code type} available to other modules and the injector. Use {@link
+   * ExposedKeyBuilder#annotatedWith(Class) annotatedWith()} to expose {@code type} with a binding
+   * annotation.
+   */
   protected final <T> ExposedKeyBuilder expose(Class<T> type) {
     checkState(exposes != null, "Cannot expose %s, private module is not ready");
     Expose<T> expose = new Expose<T>(sourceProvider.get(), readyProvider, Key.get(type));
@@ -147,6 +191,11 @@
     return expose;
   }
 
+  /**
+   * Makes a binding for {@code type} available to other modules and the injector. Use {@link
+   * ExposedKeyBuilder#annotatedWith(Class) annotatedWith()} to expose {@code type} with a binding
+   * annotation.
+   */
   protected final <T> ExposedKeyBuilder expose(TypeLiteral<T> type) {
     checkState(exposes != null, "Cannot expose %s, private module is not ready");
     Expose<T> expose = new Expose<T>(sourceProvider.get(), readyProvider, Key.get(type));
@@ -154,14 +203,13 @@
     return expose;
   }
 
+  /** Qualifies an exposed type with a binding annotation. */
   public interface ExposedKeyBuilder {
     void annotatedWith(Class<? extends Annotation> annotationType);
     void annotatedWith(Annotation annotation);
   }
 
-  /**
-   * A binding from the private injector exposed to the public injector.
-   */
+  /** A binding from the private injector exposed to the public injector. */
   private static class Expose<T> implements ExposedKeyBuilder, Provider<T> {
     private final Object source;
     private final Provider<Ready> readyProvider;
@@ -200,9 +248,7 @@
     }
   }
 
-  /**
-   * Returns the set of keys bound by {@code elements}.
-   */
+  /** Returns the set of keys bound by {@code elements}. */
   private Set<Key<?>> getBoundKeys(Iterable<? extends Element> elements) {
     final Set<Key<?>> privatelyBoundKeys = Sets.newHashSet();
     ElementVisitor<Void> visitor = new DefaultElementVisitor<Void>() {
diff --git a/src/com/google/inject/spi/ProviderMethods.java b/src/com/google/inject/spi/ProviderMethods.java
deleted file mode 100644
index 53506b0..0000000
--- a/src/com/google/inject/spi/ProviderMethods.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/**
- * Copyright (C) 2007 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.inject.spi;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import com.google.common.collect.Lists;
-import com.google.inject.Binder;
-import com.google.inject.Key;
-import com.google.inject.Module;
-import com.google.inject.Provider;
-import com.google.inject.Provides;
-import com.google.inject.TypeLiteral;
-import com.google.inject.binder.AnnotatedBindingBuilder;
-import com.google.inject.internal.Annotations;
-import com.google.inject.internal.Errors;
-import com.google.inject.internal.TypeResolver;
-import com.google.inject.util.Modules;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Type;
-import java.util.List;
-
-/**
- * Creates bindings to methods annotated with {@literal @}{@link Provides}. Use the scope and
- * binding annotations on the provider method to configure the binding.
- */
-class ProviderMethods {
-
-  /**
-   * Returns a module which creates bindings for provider methods from the
-   * given object.
-   */
-  static Module from(Object providers) {
-    // avoid infinite recursion, since installing a module always installs itself
-    if (providers instanceof ProviderMethodsModule) {
-      return Modules.EMPTY_MODULE;
-    }
-
-    return new ProviderMethodsModule(providers);
-  }
-
-  static class ProviderMethodsModule implements Module {
-    final Object providers;
-    final TypeResolver typeResolver;
-    Binder binder;
-
-    ProviderMethodsModule(Object providers) {
-      this.providers = checkNotNull(providers, "providers");
-      this.typeResolver = new TypeResolver(providers.getClass());
-    }
-
-    public synchronized void configure(Binder binder) {
-      checkState(this.binder == null, "Re-entry is not allowed.");
-
-      for (Class c = providers.getClass(); c != Object.class; c = c.getSuperclass()) {
-        for (Method method : c.getDeclaredMethods()) {
-          if (!method.isAnnotationPresent(Provides.class)) {
-            continue;
-          }
-
-          this.binder = binder.withSource(method);
-          try {
-            bindProviderMethod(method);
-          } finally {
-            this.binder = null;
-          }
-        }
-      }
-    }
-
-    <T> void bindProviderMethod(final Method method) {
-      Errors errors = new Errors(method);
-
-      method.setAccessible(true);
-
-      Class<? extends Annotation> scopeAnnotation
-          = Annotations.findScopeAnnotation(errors, method.getAnnotations());
-      Annotation bindingAnnotation
-          = Annotations.findBindingAnnotation(errors, method, method.getAnnotations());
-
-      final List<Provider<?>> parameterProviders = findParameterProviders(errors, method);
-
-      for (Message message : errors.getMessages()) {
-        binder.addError(message);
-      }
-
-      // Define T as the method's return type.
-      @SuppressWarnings("unchecked") TypeLiteral<T> returnType
-          = (TypeLiteral<T>) TypeLiteral.get(typeResolver.getReturnType(method));
-
-      Provider<T> provider = new Provider<T>() {
-        public T get() {
-          Object[] parameters = new Object[parameterProviders.size()];
-          for (int i = 0; i < parameters.length; i++) {
-            parameters[i] = parameterProviders.get(i).get();
-          }
-
-          try {
-            // We know this cast is safe becase T is the method's return type.
-            @SuppressWarnings({ "unchecked", "UnnecessaryLocalVariable" })
-            T result = (T) method.invoke(providers, parameters);
-            return result;
-          }
-          catch (IllegalAccessException e) {
-            throw new AssertionError(e);
-          }
-          catch (InvocationTargetException e) {
-            throw new RuntimeException(e);
-          }
-        }
-      };
-
-      AnnotatedBindingBuilder<T> builder = binder.bind(returnType);
-
-      if (bindingAnnotation != null) {
-        builder.annotatedWith(bindingAnnotation);
-      }
-
-      builder.toProvider(provider);
-
-      if (scopeAnnotation != null) {
-        builder.in(scopeAnnotation);
-      }
-    }
-
-    List<Provider<?>> findParameterProviders(Errors errors, Method method) {
-      List<Provider<?>> parameterProviders = Lists.newArrayList();
-
-      List<Type> parameterTypes = typeResolver.getParameterTypes(method);
-      Annotation[][] parameterAnnotations = method.getParameterAnnotations();
-      for (int i = 0; i < parameterTypes.size(); i++) {
-        Type parameterType = parameterTypes.get(i);
-        Annotation bindingAnnotation
-            = Annotations.findBindingAnnotation(errors, method, parameterAnnotations[i]);
-        Key<?> key = bindingAnnotation == null ? Key.get(parameterType)
-            : Key.get(parameterType, bindingAnnotation);
-        Provider<?> provider = binder.getProvider(key);
-        parameterProviders.add(provider);
-      }
-
-      return parameterProviders;
-    }
-
-    @Override public boolean equals(Object o) {
-      return o instanceof ProviderMethodsModule
-          && ((ProviderMethodsModule) o).providers == providers;
-    }
-
-    @Override public int hashCode() {
-      return providers.hashCode();
-    }
-  }
-}