All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.inject.rebind.BindingsProcessor Maven / Gradle / Ivy

Go to download

GIN (GWT INjection) brings automatic dependency injection to Google Web Toolkit client-side code. GIN is built on top of Guice and uses (a subset of) Guice's binding language.

There is a newer version: 2.1.2
Show newest version
/*
 * Copyright 2010 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.gwt.inject.rebind;

import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.inject.client.GinModule;
import com.google.gwt.inject.client.Ginjector;
import com.google.gwt.inject.client.PrivateGinModule;
import com.google.gwt.inject.client.assistedinject.FactoryModule;
import com.google.gwt.inject.rebind.adapter.GinModuleAdapter;
import com.google.gwt.inject.rebind.adapter.PrivateGinModuleAdapter;
import com.google.gwt.inject.rebind.binding.BindingFactory;
import com.google.gwt.inject.rebind.binding.Context;
import com.google.gwt.inject.rebind.binding.FactoryBinding;
import com.google.gwt.inject.rebind.reflect.MethodLiteral;
import com.google.gwt.inject.rebind.reflect.ReflectUtil;
import com.google.gwt.inject.rebind.util.MemberCollector;
import com.google.inject.ConfigurationException;
import com.google.inject.Inject;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.Elements;

import javax.inject.Provider;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * Builds up the bindings and scopes for this {@code Ginjector}.  This uses
 * Guice SPI to inspect the modules and build up details about the necessary
 * bindings in the {@link GinjectorBindings}. 
 */
@Singleton
class BindingsProcessor {
  /**
   * Collector that gathers all methods from an injector.
   */
  private final MemberCollector completeCollector;

  private final BindingFactory bindingFactory;

  /**
   * Interface of the injector that this class is implementing.
   */
  private final TypeLiteral ginjectorInterface;

  private final ErrorManager errorManager;
  private final GinjectorBindings rootGinjectorBindings;
  private final GuiceElementVisitor.GuiceElementVisitorFactory guiceElementVisitorFactory;

  private final Set> moduleClasses;

  private DoubleBindingChecker doubleBindingChecker;

  @Inject
  BindingsProcessor(Provider collectorProvider,
      @GinjectorInterfaceType Class ginjectorInterface,
      ErrorManager errorManager,
      @RootBindings GinjectorBindings rootGinjectorBindings,
      GuiceElementVisitor.GuiceElementVisitorFactory guiceElementVisitorFactory,
      BindingFactory bindingFactory,
      @ModuleClasses Set> moduleClasses,
      DoubleBindingChecker doubleBindingChecker) {
    this.bindingFactory = bindingFactory;
    this.moduleClasses = moduleClasses;
    this.ginjectorInterface = TypeLiteral.get(ginjectorInterface);
    this.errorManager = errorManager;
    this.rootGinjectorBindings = rootGinjectorBindings;
    this.guiceElementVisitorFactory = guiceElementVisitorFactory;
    this.doubleBindingChecker = doubleBindingChecker;

    completeCollector = collectorProvider.get();
    completeCollector.setMethodFilter(MemberCollector.ALL_METHOD_FILTER);
  }
  
  public void process() throws UnableToCompleteException {
    validateMethods();
    rootGinjectorBindings.setModule(ginjectorInterface.getRawType());
    rootGinjectorBindings.addUnresolvedEntriesForInjectorInterface();
    registerGinjectorBinding();

    createBindingsForModules(instantiateModules());
    errorManager.checkForError();
    
    resolveAllUnresolvedBindings(rootGinjectorBindings);
    errorManager.checkForError();

    doubleBindingChecker.checkBindings(rootGinjectorBindings);
    errorManager.checkForError();
  }
  
  /**
   * Create an explicit binding for the Ginjector.
   */
  private void registerGinjectorBinding() {
    Key ginjectorKey = Key.get(ginjectorInterface);
    rootGinjectorBindings.addBinding(ginjectorKey, bindingFactory.getGinjectorBinding());
  }
  
  /**
   * Create bindings for factories and resolve all implicit bindings for all 
   * unresolved bindings in the each injector.
   * 
   * 

This performs a depth-first iteration over all the nodes, and fills in the * bindings on the way up the tree. This order is important because creating * implicit bindings in a child {@link GinjectorBindings} may add dependencies to the * parent. By processing on the way up, we ensure that we only need to * process each set once. * * @param collection {@link GinjectorBindings} to resolve bindings for * @throws UnableToCompleteException if binding failed */ private void resolveAllUnresolvedBindings(GinjectorBindings collection) throws UnableToCompleteException { // Create known/explicit bindings before descending into children. This ensures that they are // available to any children that may need to depend on them. createBindingsForFactories(collection); // Visit all children and resolve bindings as appropriate. This visitation may add implicit // bindings (and dependencies) to this ginjector for (GinjectorBindings child : collection.getChildren()) { resolveAllUnresolvedBindings(child); } // Resolve bindings within this ginjector and validate that everything looks OK. collection.resolveBindings(); } private void createBindingsForFactories(GinjectorBindings bindings) { for (final FactoryModule factoryModule : bindings.getFactoryModules()) { FactoryBinding binding; try { binding = bindingFactory.getFactoryBinding( factoryModule.getBindings(), factoryModule.getFactoryType(), Context.forText(factoryModule.getSource())); } catch (ConfigurationException e) { errorManager.logError("Factory %s could not be created", e, factoryModule.getFactoryType()); continue; } bindings.addBinding(factoryModule.getFactoryType(), binding); } } private void validateMethods() throws UnableToCompleteException { for (MethodLiteral method : completeCollector.getMethods(ginjectorInterface)) { List> parameters = method.getParameterTypes(); if (parameters.size() > 1) { errorManager.logError("Injector methods cannot have more than one parameter, found: %s", method); } if (parameters.size() == 1) { // Member inject method. Class paramType = parameters.get(0).getRawType(); if (!ReflectUtil.isClassOrInterface(paramType)) { errorManager.logError( "Injector method parameter types must be a class or interface, found: %s", method); } if (!method.getReturnType().getRawType().equals(Void.TYPE)) { errorManager.logError( "Injector methods with a parameter must have a void return type, found: %s", method); } } else if (method.getReturnType().getRawType().equals(Void.TYPE)) { // Constructor injection. errorManager.logError("Injector methods with no parameters cannot return void"); } } errorManager.checkForError(); } private void createBindingsForModules(List modules) { GuiceElementVisitor visitor = guiceElementVisitorFactory.create(rootGinjectorBindings); visitor.visitElementsAndReportErrors(Elements.getElements(modules)); } private List instantiateModules() { List modules = new ArrayList(); for (Class clazz : moduleClasses) { Module module = instantiateModuleClass(clazz); if (module != null) { modules.add(module); } } return modules; } private Module instantiateModuleClass(Class moduleClass) { try { Constructor constructor = moduleClass.getDeclaredConstructor(); try { constructor.setAccessible(true); if (PrivateGinModule.class.isAssignableFrom(moduleClass)) { return new PrivateGinModuleAdapter((PrivateGinModule) constructor.newInstance(), rootGinjectorBindings); } else { return new GinModuleAdapter(constructor.newInstance(), rootGinjectorBindings); } } finally { constructor.setAccessible(false); } } catch (IllegalAccessException e) { errorManager.logError("Error creating module: " + moduleClass, e); } catch (InstantiationException e) { errorManager.logError("Error creating module: " + moduleClass, e); } catch (NoSuchMethodException e) { errorManager.logError("Error creating module: " + moduleClass, e); } catch (InvocationTargetException e) { errorManager.logError("Error creating module: " + moduleClass, e); } return null; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy