
com.google.gwt.inject.rebind.GuiceElementVisitor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gin Show documentation
Show all versions of gin Show documentation
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.
/*
* Copyright 2011 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.TreeLogger;
import com.google.gwt.inject.rebind.binding.BindingFactory;
import com.google.gwt.inject.rebind.binding.Context;
import com.google.gwt.inject.rebind.binding.ExposedChildBinding;
import com.google.gwt.inject.rebind.util.PrettyPrinter;
import com.google.inject.Inject;
import com.google.inject.Key;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.spi.DefaultElementVisitor;
import com.google.inject.spi.Element;
import com.google.inject.spi.Message;
import com.google.inject.spi.PrivateElements;
import com.google.inject.spi.ProviderLookup;
import com.google.inject.spi.StaticInjectionRequest;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Gathers elements and adds them to a {@link GinjectorBindings}.
*/
public class GuiceElementVisitor extends DefaultElementVisitor {
/**
* Interface for use with Assisted Injection for creating {@link GuiceElementVisitor}
*/
public interface GuiceElementVisitorFactory {
GuiceElementVisitor create(GinjectorBindings bindingsCollection);
}
private final List messages = new ArrayList();
private final TreeLogger logger;
private final GuiceElementVisitor.GuiceElementVisitorFactory guiceElementVisitorFactory;
private final GinjectorBindings bindings;
private final ErrorManager errorManager;
private final BindingFactory bindingFactory;
private Iterator children;
private GuiceBindingVisitorFactory bindingVisitorFactory;
@Inject
public GuiceElementVisitor(TreeLogger logger,
GuiceElementVisitorFactory guiceElementVisitorFactory,
GuiceBindingVisitorFactory bindingVisitorFactory,
ErrorManager errorManager,
@Assisted GinjectorBindings bindings, BindingFactory bindingFactory) {
this.logger = logger;
this.guiceElementVisitorFactory = guiceElementVisitorFactory;
this.bindingVisitorFactory = bindingVisitorFactory;
this.errorManager = errorManager;
this.bindings = bindings;
this.bindingFactory = bindingFactory;
}
public void visitElementsAndReportErrors(List elements) {
visitElements(elements);
// Capture any binding errors, any of which we treat as fatal.
if (!messages.isEmpty()) {
for (Message message : messages) {
// tostring has both source and message so use that
errorManager.logError(message.toString(), message.getCause());
}
}
}
private void visitElements(List elements) {
// We take advantage of the fact that iterating over the PrivateElements should
// happen in the same order that the modules were installed. We match each PrivateElements
// up with the {@link GinjectorBindings} that were created in the adapter.
children = bindings.getChildren().iterator();
for (Element element : elements) {
element.acceptVisitor(this);
}
}
public Void visit(com.google.inject.Binding command) {
GuiceBindingVisitor bindingVisitor = bindingVisitorFactory.create(
command.getKey(), messages, bindings);
PrettyPrinter.log(logger, TreeLogger.DEBUG, "Adding pin for %s in %s because %s",
command.getKey(), bindings, command);
// If we visit a binding for a key, we pin it to the current ginjector,
// since it indicates that the user explicitly asked for it to be placed
// there.
bindings.addPin(command.getKey());
command.acceptTargetVisitor(bindingVisitor);
command.acceptScopingVisitor(bindingVisitor);
return null;
}
public Void visit(Message message) {
messages.add(message);
return null;
}
public Void visit(ProviderLookup providerLookup) {
// Ignore provider lookups for now
// TODO(bstoler): I guess we should error if you try to lookup a provider
// that is not bound?
return null;
}
protected Void visitOther(Element element) {
visit(new Message(element.getSource(), "Ignoring unsupported Module element: " + element));
return null;
}
public Void visit(StaticInjectionRequest staticInjectionRequest) {
bindings.addStaticInjectionRequest(
staticInjectionRequest.getType(),
staticInjectionRequest.getSource());
return null;
}
public Void visit(PrivateElements privateElements) {
GinjectorBindings childCollection = children.next();
// Add information about the elements in the child ginjector to the child bindings
// TODO(bchambers): Use the tree loggers more intelligently -- when visiting
// a child bindings collection, we should create a new branch. This is slightly
// complicated because we process in two stages -- once here where we
// add explicit bindings (and record implicit dependencies), and again later
// to resolve the implicit dependencies.
GuiceElementVisitor childVisitor = guiceElementVisitorFactory.create(childCollection);
childVisitor.visitElements(privateElements.getElements());
messages.addAll(childVisitor.getMessages());
// Add information about the exposed elements in child to the current binding collection
for (Key> key : privateElements.getExposedKeys()) {
ExposedChildBinding childBinding =
bindingFactory.getExposedChildBinding(key, childCollection,
Context.forElement(privateElements));
// The child must have an explicit binding or pin for anything it exposes.
//
// Note that this is correct only because the
// GuiceElementVisitor runs before any synthetic bindings are
// inserted into the GinjectorBindings (more specifically,
// before implicit bindings are generated). Otherwise,
// isBound() might return true for keys that weren't explicitly bound.
//
// If the above invariant is violated, the effect will be to
// bypass this error in some cases. The offending key should
// still generate an error, but it will not be as clearly
// described.
if (!(childCollection.isBound(key) || childCollection.isPinned(key))) {
errorManager.logError(
"Key %s was exposed from but not bound in %s. Did you forget to call bind()?",
key, childCollection);
}
PrettyPrinter.log(logger, TreeLogger.TRACE, "Child binding for %s in %s: %s", key, bindings, childBinding);
bindings.addBinding(key, childBinding);
}
return null;
}
public List getMessages() {
return messages;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy