package tc.oc.commons.core.inject; import com.google.inject.Binding; import com.google.inject.Key; import com.google.inject.spi.BindingTargetVisitor; import com.google.inject.spi.ConstructorBinding; import com.google.inject.spi.ConvertedConstantBinding; import com.google.inject.spi.DisableCircularProxiesOption; import com.google.inject.spi.Element; import com.google.inject.spi.ElementVisitor; import com.google.inject.spi.ExposedBinding; import com.google.inject.spi.InjectionRequest; import com.google.inject.spi.InstanceBinding; import com.google.inject.spi.InterceptorBinding; import com.google.inject.spi.LinkedKeyBinding; import com.google.inject.spi.MembersInjectorLookup; import com.google.inject.spi.Message; import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding; import com.google.inject.spi.PrivateElements; import com.google.inject.spi.ProviderBinding; import com.google.inject.spi.ProviderInstanceBinding; import com.google.inject.spi.ProviderKeyBinding; import com.google.inject.spi.ProviderLookup; import com.google.inject.spi.ProvisionListenerBinding; import com.google.inject.spi.RequireAtInjectOnConstructorsOption; import com.google.inject.spi.RequireExactBindingAnnotationsOption; import com.google.inject.spi.RequireExplicitBindingsOption; import com.google.inject.spi.ScopeBinding; import com.google.inject.spi.StaticInjectionRequest; import com.google.inject.spi.TypeConverterBinding; import com.google.inject.spi.TypeListenerBinding; import com.google.inject.spi.UntargettedBinding; /** * Generates a descriptive {@link Message} for every visited element, and passes it to {@link #visit(Message)}. */ public abstract class ElementInspector<V> implements ElementVisitor<V> { protected V message(Object source, String text) { return visit(new Message(source, text)); } protected V message(Element element, String text) { return message(element.getSource(), text); } @Override public <T> V visit(Binding<T> binding) { final String text = "Binding " + binding.getKey() + " to " + binding.acceptTargetVisitor(new BindingTargetVisitor<T, String>() { @Override public String visit(InstanceBinding<? extends T> binding) { return "instance " + binding.getInstance(); } @Override public String visit(ProviderInstanceBinding<? extends T> binding) { return "provider instance " + binding.getUserSuppliedProvider(); } @Override public String visit(ProviderKeyBinding<? extends T> binding) { return "provider key " + binding.getProviderKey(); } @Override public String visit(LinkedKeyBinding<? extends T> binding) { return "linked key " + binding.getLinkedKey(); } @Override public String visit(ExposedBinding<? extends T> binding) { return "exposed key from private environment"; } @Override public String visit(UntargettedBinding<? extends T> binding) { return "itself"; } @Override public String visit(ConstructorBinding<? extends T> binding) { return "constructor " + binding.getConstructor(); } @Override public String visit(ConvertedConstantBinding<? extends T> binding) { return "converted value " + binding.getValue(); } @Override public String visit(ProviderBinding<? extends T> binding) { return "provider of key " + binding.getProvidedKey(); } }); return message(binding, text); } @Override public V visit(InterceptorBinding binding) { return message(binding, "Binding interceptors " + binding.getInterceptors() + " to methods matching " + binding.getMethodMatcher() + " on classes matching " + binding.getClassMatcher()); } @Override public V visit(ScopeBinding binding) { return message(binding, "Binding scope annotation " + binding.getAnnotationType() + " to scope " + binding.getScope()); } @Override public V visit(TypeConverterBinding binding) { return message(binding, "Binding type converter " + binding.getTypeConverter() + " to classes matching " + binding.getTypeMatcher()); } @Override public V visit(InjectionRequest<?> request) { return message(request, "Requesting injection of " + request.getType() + " for instance " + request.getInstance()); } @Override public V visit(StaticInjectionRequest request) { return message(request, "Requesting static injection for " + request.getType()); } @Override public <T> V visit(ProviderLookup<T> lookup) { return message(lookup, "Looking up provider " + lookup.getProvider() + " for key " + lookup.getKey()); } @Override public <T> V visit(MembersInjectorLookup<T> lookup) { return message(lookup, "Looking up members injector " + lookup.getMembersInjector() + " for type " + lookup.getType()); } @Override public V visit(PrivateElements elements) { final V result = message(elements, "Binding private module"); for(Key<?> key : elements.getExposedKeys()) { message(elements.getExposedSource(key), " Exposing key " + key); } for(Element element : elements.getElements()) { element.acceptVisitor(new ElementInspector<V>() { @Override public V visit(Message message) { return ElementInspector.this.visit(new Message(message.getSources(), " " + message.getMessage(), message.getCause())); } }); } return result; } @Override public V visit(TypeListenerBinding binding) { return message(binding, "Binding type listener " + binding.getListener() + " for types matching " + binding.getTypeMatcher()); } @Override public V visit(ProvisionListenerBinding binding) { return message(binding, "Binding provision listeners " + binding.getListeners() + " for bindings matching " + binding.getBindingMatcher()); } @Override public V visit(RequireExplicitBindingsOption option) { return message(option, "Requiring explicit bindings"); } @Override public V visit(DisableCircularProxiesOption option) { return message(option, "Disabling circular proxies"); } @Override public V visit(RequireAtInjectOnConstructorsOption option) { return message(option, "Requiring explicit @Inject on constructors"); } @Override public V visit(RequireExactBindingAnnotationsOption option) { return message(option, "Requiring exact binding annotations"); } @Override public V visit(ModuleAnnotatedMethodScannerBinding binding) { return message(binding, "Scanning modules for methods annotated with " + binding.getScanner().annotationClasses()); } }