Skip to content

Instantly share code, notes, and snippets.

@vorburger
Created January 27, 2014 16:48
Show Gist options
  • Select an option

  • Save vorburger/8652290 to your computer and use it in GitHub Desktop.

Select an option

Save vorburger/8652290 to your computer and use it in GitHub Desktop.
InjectorToString.java - Guice Injector toString - nicer than built-in massive one line dump (currently unfinished)
/**
* Copyright (C) 2014 Michael Vorburger
*
* 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 ch.vorburger.guice.util;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map.Entry;
import java.util.Set;
import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Scope;
import com.google.inject.spi.ConstructorBinding;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.ProviderInstanceBinding;
import com.google.inject.spi.TypeConverterBinding;
/**
* Utility to dump the Guice Injector toString().
*
* A little more readable than the OOB massive one line injector.toString()... ;-)
*
* @author Michael Vorburger
*/
public class InjectorToString {
// TODO actually finish it some time, may be
// TODO [HIGH] better nested intention (e.g. for Dependencies).. see how Xtend does it for http://www.eclipse.org/xtend/documentation.html#templates ?
// TODO [HIGH] ignore Provider (but only if duplicates!)..
// TODO [MEDIUM] separate explicit and just-in-time.. how? Note getBindings() vs. getAllBindings().. can we use set substraction?
// TODO [MEDIUM] helper, extensible, to shorten annotations (or any type names).. e.g. @com.google.inject.name.Named ==> @Named, @com.google.inject.Provider ==> c.g.i.Provider (still from logger..)
// TODO [MEDIUM] recursion risk? Note InjectorTest.testToStringDoesNotInfinitelyRecurse() ...
// TODO [LOW] Builder thing, with options like ignoreProviderDuplicates
// TODO [LOW] better to use Writer 1st args, instead of StringBuffer?
protected static final String UNKNOWN_SOURCE = "[unknown source]";
public String toString(Injector injector) {
StringBuilder sb = new StringBuilder();
printInjector(sb, injector);
return sb.toString();
}
protected void printInjector(StringBuilder sb, Injector injector) {
sb.append(injector.toString()); // TODO remove again at the end, just for now..
sb.append('\n');
Set<Entry<Key<?>, Binding<?>>> allBindings = injector.getAllBindings().entrySet();
int i = 0;
for (Entry<Key<?>, Binding<?>> entry : allBindings) {
// TODO factor out methods.. making it easier to overload this
// TOOD align nicely.. first find longest key..
sb.append(++i);
sb.append(". ");
Key<?> key = entry.getKey();
if (key.hasAttributes()) {
sb.append(key.getAnnotation().toString());
sb.append("\n ");
}
Type type = key.getTypeLiteral().getType();
sb.append(type.toString());
sb.append(" : ");
Binding<?> value = entry.getValue();
sb.append(value.toString());// TODO remove
sb.append("\n ");
printProviderBinding(sb, value.getProvider());
printSource(sb, value.getSource());
sb.append('\n');
}
printTypeConverterBindings(sb, injector.getTypeConverterBindings());
printScopeBindings(sb, injector.getScopeBindings().entrySet());
printParent(sb, injector.getParent());
}
protected void printProviderBinding(StringBuilder sb, Provider<?> provider) {
sb.append("?? ");
sb.append(provider.toString());
if (provider instanceof HasDependencies) {
Set<Dependency<?>> dependencies = ((HasDependencies) provider).getDependencies();
printDependencies(sb, dependencies);
}
// if (provider instanceof Binding) {
// Binding<?> binding = (Binding<?>) provider;
// }
if (provider instanceof ConstructorBinding) {
ConstructorBinding constructorBinding = (ConstructorBinding) provider;
printInjectionPoint(sb, constructorBinding.getConstructor());
printInjectionPoints(sb, constructorBinding.getInjectableMembers());
// TODO } else if (provider instanceof ConvertedConstantBinding) {
// TODO } else if (provider instanceof ExposedBinding) {
// TODO } else if (provider instanceof InstanceBinding) {
// TODO } else if (provider instanceof LinkedKeyBinding) {
//
// TODO } else if (provider instanceof ProviderBinding) {
} else if (provider instanceof ProviderInstanceBinding) {
ProviderInstanceBinding pib = (ProviderInstanceBinding) provider;
sb.append("ProviderInstance: ");
printProviderInstance(sb, pib.getProviderInstance());
printInjectionPoints(sb, pib.getInjectionPoints());
// TODO } else if (provider instanceof ProviderKeyBinding) {
// TODO } else if (provider instanceof UntargettedBinding) {
} else {
sb.append("WARN: No handling available for " + provider.getClass());
}
sb.append(provider.getClass());
}
protected void printDependencies(StringBuilder sb, Collection<Dependency<?>> dependencies) {
printSectionHeaderIfNonEmptyCollection(sb, dependencies, "Dependencies");
for (Dependency<?> dependency : dependencies) {
sb.append(dependency.getParameterIndex());
sb.append("=");
printInjectionPoint(sb, dependency.getInjectionPoint());
}
}
protected void printInjectionPoints(StringBuilder sb, Set<InjectionPoint> injectionPoints) {
printSectionHeaderIfNonEmptyCollection(sb, injectionPoints, "InjectionPoints");
for (InjectionPoint injectionPoint: injectionPoints) {
printInjectionPoint(sb, injectionPoint);
}
}
protected void printInjectionPoint(StringBuilder sb, InjectionPoint injectionPoint) {
sb.append(injectionPoint.getDeclaringType());
sb.append(" -- "); // ?
sb.append(injectionPoint.getMember());
printDependencies(sb, injectionPoint.getDependencies());
}
protected void printProviderInstance(StringBuilder sb, Provider providerInstance) {
sb.append(providerInstance.toString());
}
protected void printTypeConverterBindings(StringBuilder sb, Set<TypeConverterBinding> typeConverterBindings) {
printSectionHeaderIfNonEmptyCollection(sb, typeConverterBindings, "TypeConverterBindings");
for (TypeConverterBinding typeConverterBinding : typeConverterBindings) {
sb.append("* ");
sb.append(typeConverterBinding.getTypeMatcher().toString());
sb.append(" : ");
sb.append(typeConverterBinding.getTypeConverter().toString());
printSource(sb, typeConverterBinding.getSource());
sb.append("\n");
}
}
protected void printScopeBindings(StringBuilder sb, Set<Entry<Class<? extends Annotation>, Scope>> scopeBindings) {
printSectionHeaderIfNonEmptyCollection(sb, scopeBindings, "ScopeBindings");
for (Entry<Class<? extends Annotation>, Scope> scopeBinding : scopeBindings) {
sb.append("* @");
sb.append(scopeBinding.getKey().getName());
sb.append(" : ");
sb.append(scopeBinding.getValue().toString());
sb.append('\n');
}
}
protected void printSource(StringBuilder sb, Object source) {
String sourceText = source.toString();
if (!UNKNOWN_SOURCE.equals(sourceText)) {
sb.append("\n SRC ");
sb.append(sourceText);
}
}
// TODO [LOW] include a 1.1. 1.2. 2.1 (parent) kind of numbering
protected void printParent(StringBuilder sb, Injector parent) {
if (parent != null) {
printSectionHeader(sb, "PARENT Injector");
printInjector(sb, parent);
}
}
protected void printSectionHeaderIfNonEmptyCollection(StringBuilder sb, Collection<?> collection, String title) {
if (!collection.isEmpty())
printSectionHeader(sb, title);
}
protected void printSectionHeader(StringBuilder sb, String title) {
sb.append("\n");
sb.append(title);
sb.append(":\n");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment