/*
* 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.inject.rebind.adapter.GwtDotCreateProvider;
import com.google.gwt.inject.rebind.binding.BindConstantBinding;
import com.google.gwt.inject.rebind.binding.BindingFactory;
import com.google.gwt.inject.rebind.binding.Context;
import com.google.gwt.inject.rebind.binding.Dependency;
import com.google.gwt.inject.rebind.util.PrettyPrinter;
import com.google.inject.Key;
import com.google.inject.Scope;
import com.google.inject.Singleton;
import com.google.inject.internal.ProviderMethod;
import com.google.inject.spi.BindingScopingVisitor;
import com.google.inject.spi.DefaultBindingTargetVisitor;
import com.google.inject.spi.Element;
import com.google.inject.spi.InstanceBinding;
import com.google.inject.spi.LinkedKeyBinding;
import com.google.inject.spi.Message;
import com.google.inject.spi.ProviderInstanceBinding;
import com.google.inject.spi.ProviderKeyBinding;
import com.google.inject.spi.UntargettedBinding;
import javax.inject.Provider;
import java.lang.annotation.Annotation;
import java.util.List;
/**
* Gathers information about Guice Bindings and adds the information to a {@link GinjectorBindings}.
*/
public class GuiceBindingVisitor<T> extends DefaultBindingTargetVisitor<T, Void>
implements BindingScopingVisitor<Void> {
private final Key<T> targetKey;
private final List<Message> messages;
private final GinjectorBindings bindingsCollection;
private final BindingFactory bindingFactory;
public GuiceBindingVisitor(Key<T> targetKey, List<Message> messages,
GinjectorBindings bindingsCollection, BindingFactory bindingFactory) {
this.targetKey = targetKey;
this.messages = messages;
this.bindingsCollection = bindingsCollection;
this.bindingFactory = bindingFactory;
}
public Void visit(ProviderKeyBinding<? extends T> providerKeyBinding) {
Context context = Context.forElement(providerKeyBinding);
bindingsCollection.addBinding(
targetKey,
bindingFactory.getBindProviderBinding(
providerKeyBinding.getProviderKey(), providerKeyBinding.getKey(), context));
return null;
}
public Void visit(ProviderInstanceBinding<? extends T> providerInstanceBinding) {
// Detect provider methods and handle them
// TODO(bstoler): Update this when the SPI explicitly has a case for
// provider methods
Provider<? extends T> provider = providerInstanceBinding.getProviderInstance();
if (provider instanceof ProviderMethod) {
Context context = Context.forElement(providerInstanceBinding);
bindingsCollection.addBinding(targetKey,
bindingFactory.getProviderMethodBinding((ProviderMethod<?>) provider, context));
return null;
}
if (provider instanceof GwtDotCreateProvider) {
addImplicitBinding(providerInstanceBinding);
return null;
}
// OTt, use the normal default handler (and error)
return super.visit(providerInstanceBinding);
}
public Void visit(LinkedKeyBinding<? extends T> linkedKeyBinding) {
Context context = Context.forElement(linkedKeyBinding);
bindingsCollection.addBinding(targetKey,
bindingFactory.getBindClassBinding(linkedKeyBinding.getLinkedKey(), targetKey, context));
return null;
}
public Void visit(InstanceBinding<? extends T> instanceBinding) {
T instance = instanceBinding.getInstance();
if (BindConstantBinding.isConstantKey(targetKey)) {
Context context = Context.forElement(instanceBinding);
bindingsCollection.addBinding(targetKey,
bindingFactory.getBindConstantBinding(targetKey, instance, context));
} else {
messages.add(new Message(instanceBinding.getSource(),
PrettyPrinter.format("Instance binding not supported; key=%s, inst=%s",
targetKey, instance)));
}
return null;
}
public Void visit(UntargettedBinding<? extends T> untargettedBinding) {
addImplicitBinding(untargettedBinding);
return null;
}
private void addImplicitBinding(Element sourceElement) {
bindingsCollection.addDependency(new Dependency(Dependency.GINJECTOR, targetKey,
Context.forElement(sourceElement).toString()));
}
protected Void visitOther(com.google.inject.Binding<? extends T> binding) {
messages.add(new Message(binding.getSource(), PrettyPrinter.format(
"Unsupported binding provided for key: %s: %s", targetKey, binding)));
return null;
}
public Void visitEagerSingleton() {
bindingsCollection.putScope(targetKey, GinScope.EAGER_SINGLETON);
return null;
}
// TODO(schmitt): We don't support this right now in any case, but it's
// strange to be using the Guice Scope instead of javax.inject.Scope
public Void visitScope(Scope scope) {
messages.add(new Message(PrettyPrinter.format("Explicit scope unsupported: key=%s scope=%s",
targetKey, scope)));
return null;
}
public Void visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
if (scopeAnnotation == Singleton.class || scopeAnnotation == javax.inject.Singleton.class) {
bindingsCollection.putScope(targetKey, GinScope.SINGLETON);
} else {
messages.add(new Message(PrettyPrinter.format("Unsupported scope annotation: key=%s scope=%s",
targetKey, scopeAnnotation)));
}
return null;
}
public Void visitNoScoping() {
bindingsCollection.putScope(targetKey, GinScope.NO_SCOPE);
return null;
}
}