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

com.google.inject.internal.Indexer Maven / Gradle / Ivy

package com.google.inject.internal;

import com.google.common.base.Objects;
import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Scope;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.BindingScopingVisitor;
import com.google.inject.spi.ConstructorBinding;
import com.google.inject.spi.ConvertedConstantBinding;
import com.google.inject.spi.DefaultBindingTargetVisitor;
import com.google.inject.spi.ExposedBinding;
import com.google.inject.spi.InstanceBinding;
import com.google.inject.spi.LinkedKeyBinding;
import com.google.inject.spi.ProviderBinding;
import com.google.inject.spi.ProviderInstanceBinding;
import com.google.inject.spi.ProviderKeyBinding;
import com.google.inject.spi.UntargettedBinding;

import java.lang.annotation.Annotation;

/**
 * Visits bindings to return a {@code IndexedBinding} that can be used to emulate the binding
 * deduplication that Guice internally performs.
 *
 * 

Note: simply using equals/hashCode on the BindingImpls doesn't work because they all have * unique annotations. This works around that by reimplementing equality semantics that ignores * {@link Element#uniqueId()}. A better solution might be to introduce the idea of an 'anonymous' * binding to guice, that might support this usecase directly. */ public class Indexer extends DefaultBindingTargetVisitor implements BindingScopingVisitor { private static final Object EAGER_SINGLETON = new Object(); private final Injector injector; public Indexer(Injector injector) { this.injector = injector; } public boolean isIndexable(Binding binding) { return binding.getKey().getAnnotation() instanceof Element; } private Object scope(Binding binding) { return binding.acceptScopingVisitor(this); } @Override public IndexedBinding visit(ConstructorBinding binding) { return new IndexedBinding(binding, BindingType.CONSTRUCTOR, scope(binding), binding.getConstructor()); } @Override public IndexedBinding visit( ConvertedConstantBinding binding) { return new IndexedBinding(binding, BindingType.CONSTANT, scope(binding), binding.getValue()); } @Override public IndexedBinding visit(ExposedBinding binding) { return new IndexedBinding(binding, BindingType.EXPOSED, scope(binding), binding); } @Override public IndexedBinding visit(InstanceBinding binding) { return new IndexedBinding(binding, BindingType.INSTANCE, scope(binding), binding.getInstance()); } @Override public IndexedBinding visit(LinkedKeyBinding binding) { return new IndexedBinding(binding, BindingType.LINKED_KEY, scope(binding), binding.getLinkedKey()); } @Override public IndexedBinding visit(ProviderBinding binding) { return new IndexedBinding(binding, BindingType.PROVIDED_BY, scope(binding), injector.getBinding(binding.getProvidedKey())); } @Override public IndexedBinding visit(ProviderInstanceBinding binding) { return new IndexedBinding(binding, BindingType.PROVIDER_INSTANCE, scope(binding), binding.getUserSuppliedProvider()); } @Override public IndexedBinding visit(ProviderKeyBinding binding) { return new IndexedBinding(binding, BindingType.PROVIDER_KEY, scope(binding), binding.getProviderKey()); } @Override public IndexedBinding visit(UntargettedBinding binding) { return new IndexedBinding(binding, BindingType.UNTARGETTED, scope(binding), null); } @Override public Object visitEagerSingleton() { return EAGER_SINGLETON; } @Override public Object visitNoScoping() { return Scopes.NO_SCOPE; } @Override public Object visitScope(Scope scope) { return scope; } @Override public Object visitScopeAnnotation(Class scopeAnnotation) { return scopeAnnotation; } enum BindingType { INSTANCE, PROVIDER_INSTANCE, PROVIDER_KEY, LINKED_KEY, UNTARGETTED, CONSTRUCTOR, CONSTANT, EXPOSED, PROVIDED_BY, } public static class IndexedBinding { final String annotationName; final Element.Type annotationType; final TypeLiteral typeLiteral; final Object scope; final BindingType type; final Object extraEquality; public IndexedBinding(Binding binding, BindingType type, Object scope, Object extraEquality) { this.scope = scope; this.type = type; this.extraEquality = extraEquality; this.typeLiteral = binding.getKey().getTypeLiteral(); Element annotation = (Element) binding.getKey().getAnnotation(); this.annotationName = annotation.setName(); this.annotationType = annotation.type(); } @Override public boolean equals(Object obj) { if (!(obj instanceof IndexedBinding)) { return false; } IndexedBinding o = (IndexedBinding) obj; return type == o.type && Objects.equal(scope, o.scope) && typeLiteral.equals(o.typeLiteral) && annotationType == o.annotationType && annotationName.equals(o.annotationName) && Objects.equal(extraEquality, o.extraEquality); } @Override public int hashCode() { return Objects.hashCode(type, scope, typeLiteral, annotationType, annotationName, extraEquality); } } }