com.google.gwt.inject.rebind.util.PrettyPrinter 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.
The newest version!
/*
* 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.util;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.inject.rebind.binding.Dependency;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import java.lang.annotation.Annotation;
import java.util.List;
/**
* Pretty-printer that formats internal types for human consumption in error
* messages.
*
* {@link #format(String, Object...)} acts like {@link String#format}, except
* that it detects and pretty-prints the following argument types:
*
*
* - {@link Class}: formatted as "org.example.Class$SubClass"
* - {@link Key}: formatted as "@org.example.Annotation org.example.Class$SubClass"
* - {@link List
}: formatted as a dependency path preceded by a newline. If
* the path begins at {@link Dependency.GINJECTOR}, that key is hidden, and the context
* of the outgoing dependency is given as the context of the first key in the displayed
* path.
*
*
* All other arguments are passed unchanged to {@link String#format}.
*/
public final class PrettyPrinter {
private PrettyPrinter() {
}
/**
* Log a pretty-printed message if the given log level is active. The message
* is only formatted if it will be logged.
*/
public static void log(TreeLogger logger, TreeLogger.Type type, String formatString,
Object... args) {
if (logger.isLoggable(type)) {
logger.log(type, format(formatString, args));
}
}
/**
* Generate a string based on a format template as {@link String#format}
* would, using the pretty-printing rules specified in the class
* documentation.
*/
public static String format(String formatString, Object... args) {
// Rewrites the varargs so that objects that need special formatting are
// replaced with formatted strings, then hands off to {@link String#format}.
Object[] formattedArgs = new Object[args.length];
for (int i = 0; i < args.length; ++i) {
formattedArgs[i] = formatObject(args[i]);
}
return String.format(formatString, (Object[]) formattedArgs);
}
/**
* Pretty-print a single object.
*/
private static Object formatObject(Object object) {
if (object instanceof Class) {
return formatArg((Class>) object);
} else if (object instanceof Key) {
return formatArg((Key>) object);
} else if (object instanceof List) {
List> list = (List>) object;
// Empirically check if this is a List.
boolean allDependencies = true;
for (Object entry : list) {
if (!(entry instanceof Dependency)) {
allDependencies = false;
break;
}
}
if (allDependencies) {
return formatArg((List) list);
} else {
return object;
}
} else {
return object;
}
}
private static String formatArg(Class> type) {
// Make sure classes are formatted in a manner that's consistent with type
// literals.
return TypeLiteral.get(type).toString();
}
private static String formatArg(Key> key) {
StringBuilder builder = new StringBuilder();
formatArgTo(key, builder);
return builder.toString();
}
/**
* Formats a list of dependencies as a dependency path; see the class
* comments.
*/
private static String formatArg(List path) {
StringBuilder builder = new StringBuilder();
formatArgTo(path, builder);
return builder.toString();
}
private static void formatArgTo(Key> key, StringBuilder builder) {
Annotation annotation = key.getAnnotation();
if (annotation != null) {
builder.append(annotation);
builder.append(" ");
} else if (key.getAnnotationType() != null) {
builder.append("@");
builder.append(formatArg(key.getAnnotationType()));
builder.append(" ");
}
builder.append(key.getTypeLiteral());
}
/**
* Formats a list of dependencies as a dependency path; see the class
* comments.
*/
private static void formatArgTo(List path, StringBuilder builder) {
if (path.isEmpty()) {
return;
}
builder.append("\n");
boolean first = true;
Key> previousTarget = null; // For sanity-checking.
for (Dependency dependency : path) {
Key> source = dependency.getSource();
Key> target = dependency.getTarget();
// Sanity-check.
if (previousTarget != null && !previousTarget.equals(source)) {
throw new IllegalArgumentException("Dependency list is not a path.");
}
// There are two possible overall shapes of the list:
//
// If it starts with GINJECTOR, we get this:
//
// Key1 [context]
// -> Key2 [context]
// ...
//
// Otherwise (e.g., if we're dumping a cycle), we get this:
//
// Key1
// -> Key2 [context]
// -> Key3 [context]
// ...
if (first) {
if (source == Dependency.GINJECTOR) {
formatArgTo(target, builder);
builder.append(String.format(" [%s]%n", dependency.getContext()));
} else {
formatArgTo(source, builder);
builder.append("\n -> ");
formatArgTo(target, builder);
builder.append(String.format(" [%s]%n", dependency.getContext()));
}
first = false;
} else {
builder.append(" -> ");
formatArgTo(target, builder);
builder.append(String.format(" [%s]%n", dependency.getContext()));
}
previousTarget = target;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy