Home | History | Annotate | Download | only in grapher
      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 (at) gmail.com (Pete Hopkins)
     39  */
     40 public class ShortNameFactory implements NameFactory {
     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 
     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   public String getClassName(Key<?> key) {
     70     TypeLiteral<?> typeLiteral = key.getTypeLiteral();
     71     return stripPackages(typeLiteral.toString());
     72   }
     73 
     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    */
    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 
    116   protected String getFileString(StackTraceElement stackTraceElement) {
    117     return stackTraceElement.getFileName() + ":" + stackTraceElement.getLineNumber();
    118   }
    119 
    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    */
    134   private String stripPackages(String str) {
    135     return str.replaceAll("(^|[< .\\(])([a-z0-9]+\\.)*", "$1");
    136   }
    137 }
    138