1 /** 2 * Copyright (C) 2008 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.inject.grapher; 18 19 import com.google.common.base.Joiner; 20 import com.google.common.collect.Lists; 21 import com.google.inject.Key; 22 import com.google.inject.TypeLiteral; 23 import com.google.inject.internal.ProviderMethod; 24 import com.google.inject.internal.util.StackTraceElements; 25 import com.google.inject.spi.ElementSource; 26 27 import java.lang.annotation.Annotation; 28 import java.lang.reflect.Constructor; 29 import java.lang.reflect.Member; 30 import java.lang.reflect.Method; 31 import java.util.List; 32 33 /** 34 * Reasonable implementation for {@link NameFactory}. Mostly takes various 35 * {@link Object#toString()}s and strips package names out of them so that 36 * they'll fit on the graph. 37 * 38 * @author phopkins@gmail.com (Pete Hopkins) 39 */ 40 public class ShortNameFactory implements NameFactory { getMemberName(Member member)41 public String getMemberName(Member member) { 42 if (member instanceof Constructor) { 43 return "<init>"; 44 } else if (member instanceof Method) { 45 return "#" + member.getName() + "(...)"; 46 } else { 47 return member.getName(); 48 } 49 } 50 getAnnotationName(Key<?> key)51 public String getAnnotationName(Key<?> key) { 52 Annotation annotation = key.getAnnotation(); 53 Class<? extends Annotation> annotationType = key.getAnnotationType(); 54 if (annotation != null) { 55 annotationType = annotation.annotationType(); 56 57 String annotationString = annotation.toString(); 58 String canonicalName = annotationType.getName(); 59 String simpleName = annotationType.getSimpleName(); 60 61 return annotationString.replace(canonicalName, simpleName).replace("()", ""); 62 } else if (annotationType != null) { 63 return "@" + annotationType.getSimpleName(); 64 } else { 65 return ""; 66 } 67 } 68 getClassName(Key<?> key)69 public String getClassName(Key<?> key) { 70 TypeLiteral<?> typeLiteral = key.getTypeLiteral(); 71 return stripPackages(typeLiteral.toString()); 72 } 73 getInstanceName(Object instance)74 public String getInstanceName(Object instance) { 75 if (instance instanceof ProviderMethod) { 76 return getMethodString(((ProviderMethod<?>) instance).getMethod()); 77 } 78 79 if (instance instanceof CharSequence) { 80 return "\"" + instance + "\""; 81 } 82 83 try { 84 if (instance.getClass().getMethod("toString").getDeclaringClass().equals(Object.class)) { 85 return stripPackages(instance.getClass().getName()); 86 } 87 } catch (SecurityException e) { 88 throw new AssertionError(e); 89 } catch (NoSuchMethodException e) { 90 throw new AssertionError(e); 91 } 92 93 return instance.toString(); 94 } 95 96 /** 97 * Returns a name for a Guice "source" object. This will typically be either 98 * a {@link StackTraceElement} for when the binding is made to the instance, 99 * or a {@link Method} when a provider method is used. 100 */ getSourceName(Object source)101 public String getSourceName(Object source) { 102 if (source instanceof ElementSource) { 103 source = ((ElementSource) source).getDeclaringSource(); 104 } 105 if (source instanceof Method) { 106 source = StackTraceElements.forMember((Method) source); 107 } 108 109 if (source instanceof StackTraceElement) { 110 return getFileString((StackTraceElement) source); 111 } 112 113 return stripPackages(source.toString()); 114 } 115 getFileString(StackTraceElement stackTraceElement)116 protected String getFileString(StackTraceElement stackTraceElement) { 117 return stackTraceElement.getFileName() + ":" + stackTraceElement.getLineNumber(); 118 } 119 getMethodString(Method method)120 protected String getMethodString(Method method) { 121 List<String> paramStrings = Lists.newArrayList(); 122 for (Class<?> paramType : method.getParameterTypes()) { 123 paramStrings.add(paramType.getSimpleName()); 124 } 125 126 String paramString = Joiner.on(", ").join(paramStrings); 127 return "#" + method.getName() + "(" + paramString + ")"; 128 } 129 130 /** 131 * Eliminates runs of lowercase characters and numbers separated by periods. 132 * Seems to remove packages from fully-qualified type names pretty well. 133 */ stripPackages(String str)134 private String stripPackages(String str) { 135 return str.replaceAll("(^|[< .\\(])([a-z0-9]+\\.)*", "$1"); 136 } 137 } 138