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 import java.lang.annotation.Annotation; 27 import java.lang.reflect.Constructor; 28 import java.lang.reflect.Member; 29 import java.lang.reflect.Method; 30 import java.util.List; 31 32 /** 33 * Reasonable implementation for {@link NameFactory}. Mostly takes various {@link 34 * Object#toString()}s and strips package names out of them so that they'll fit on the graph. 35 * 36 * @author phopkins@gmail.com (Pete Hopkins) 37 */ 38 public class ShortNameFactory implements NameFactory { 39 @Override getMemberName(Member member)40 public String getMemberName(Member member) { 41 if (member instanceof Constructor) { 42 return "<init>"; 43 } else if (member instanceof Method) { 44 return "#" + member.getName() + "(...)"; 45 } else { 46 return member.getName(); 47 } 48 } 49 50 @Override 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 69 @Override getClassName(Key<?> key)70 public String getClassName(Key<?> key) { 71 TypeLiteral<?> typeLiteral = key.getTypeLiteral(); 72 return stripPackages(typeLiteral.toString()); 73 } 74 75 @Override getInstanceName(Object instance)76 public String getInstanceName(Object instance) { 77 if (instance instanceof ProviderMethod) { 78 return getMethodString(((ProviderMethod<?>) instance).getMethod()); 79 } 80 81 if (instance instanceof CharSequence) { 82 return "\"" + instance + "\""; 83 } 84 85 try { 86 if (instance.getClass().getMethod("toString").getDeclaringClass().equals(Object.class)) { 87 return stripPackages(instance.getClass().getName()); 88 } 89 } catch (SecurityException e) { 90 throw new AssertionError(e); 91 } catch (NoSuchMethodException e) { 92 throw new AssertionError(e); 93 } 94 95 return instance.toString(); 96 } 97 98 /** 99 * Returns a name for a Guice "source" object. This will typically be either a {@link 100 * StackTraceElement} for when the binding is made to the instance, or a {@link Method} when a 101 * provider method is used. 102 */ 103 @Override getSourceName(Object source)104 public String getSourceName(Object source) { 105 if (source instanceof ElementSource) { 106 source = ((ElementSource) source).getDeclaringSource(); 107 } 108 if (source instanceof Method) { 109 source = StackTraceElements.forMember((Method) source); 110 } 111 112 if (source instanceof StackTraceElement) { 113 return getFileString((StackTraceElement) source); 114 } 115 116 return stripPackages(source.toString()); 117 } 118 getFileString(StackTraceElement stackTraceElement)119 protected String getFileString(StackTraceElement stackTraceElement) { 120 return stackTraceElement.getFileName() + ":" + stackTraceElement.getLineNumber(); 121 } 122 getMethodString(Method method)123 protected String getMethodString(Method method) { 124 List<String> paramStrings = Lists.newArrayList(); 125 for (Class<?> paramType : method.getParameterTypes()) { 126 paramStrings.add(paramType.getSimpleName()); 127 } 128 129 String paramString = Joiner.on(", ").join(paramStrings); 130 return "#" + method.getName() + "(" + paramString + ")"; 131 } 132 133 /** 134 * Eliminates runs of lowercase characters and numbers separated by periods. Seems to remove 135 * packages from fully-qualified type names pretty well. 136 */ stripPackages(String str)137 private String stripPackages(String str) { 138 return str.replaceAll("(^|[< .\\(])([a-z0-9]+\\.)*", "$1"); 139 } 140 } 141