Cleaned up error handling. Separated ErrorHandler from source tracking. We now point directly to members when appropriate.

git-svn-id: https://google-guice.googlecode.com/svn/trunk@179 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/src/com/google/inject/AbstractErrorHandler.java b/src/com/google/inject/AbstractErrorHandler.java
index 95c5d31..44d1276 100644
--- a/src/com/google/inject/AbstractErrorHandler.java
+++ b/src/com/google/inject/AbstractErrorHandler.java
@@ -23,10 +23,10 @@
  */
 abstract class AbstractErrorHandler implements ErrorHandler {
 
-  public final void handle(String message, Object... arguments) {
+  public final void handle(Object source, String message, Object... arguments) {
     for (int i = 0; i < arguments.length; i++) {
       arguments[i] = ErrorMessages.convert(arguments[i]);
     }
-    handle(String.format(message, arguments));
+    handle(source, String.format(message, arguments));
   }
 }
diff --git a/src/com/google/inject/AbstractModule.java b/src/com/google/inject/AbstractModule.java
index 42dfd1e..ec19407 100644
--- a/src/com/google/inject/AbstractModule.java
+++ b/src/com/google/inject/AbstractModule.java
@@ -75,11 +75,11 @@
   }
 
   /**
-   * @see ContainerBuilder#scope(Class, Scope)
+   * @see ContainerBuilder#bindScope(Class, Scope)
    */
   protected void scope(Class<? extends Annotation> scopeAnnotation,
       Scope scope) {
-    builder.scope(scopeAnnotation, scope);
+    builder.bindScope(scopeAnnotation, scope);
   }
 
   /**
diff --git a/src/com/google/inject/ConstructorInjector.java b/src/com/google/inject/ConstructorInjector.java
index 6e3b0ea..6ddaf70 100644
--- a/src/com/google/inject/ConstructorInjector.java
+++ b/src/com/google/inject/ConstructorInjector.java
@@ -18,6 +18,7 @@
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
+import com.google.inject.util.StackTraceElements;
 
 /**
  * Injects constructors.
@@ -77,7 +78,8 @@
       if (constructor.getAnnotation(Inject.class) != null) {
         if (found != null) {
           container.errorHandler.handle(
-              ErrorMessages.TOO_MANY_CONSTRUCTORS, implementation);
+              StackTraceElements.forMember(found),
+              ErrorMessages.TOO_MANY_CONSTRUCTORS);
           return ContainerImpl.invalidConstructor();
         }
         found = constructor;
@@ -94,7 +96,10 @@
     }
     catch (NoSuchMethodException e) {
       container.errorHandler.handle(
-          ErrorMessages.MISSING_CONSTRUCTOR, implementation);
+          StackTraceElements.forMember(
+              implementation.getDeclaredConstructors()[0]),
+          ErrorMessages.MISSING_CONSTRUCTOR,
+          implementation);
       return ContainerImpl.invalidConstructor();
     }
   }
diff --git a/src/com/google/inject/ContainerBuilder.java b/src/com/google/inject/ContainerBuilder.java
index 2cdeef2..d9f473e 100644
--- a/src/com/google/inject/ContainerBuilder.java
+++ b/src/com/google/inject/ContainerBuilder.java
@@ -113,7 +113,7 @@
    *  we will eagerly load container-scoped objects.
    */
   public ContainerBuilder(Stage stage) {
-    scope(ContainerScoped.class, CONTAINER);
+    bindScope(ContainerScoped.class, CONTAINER);
 
     bind(Container.class).to(CONTAINER_FACTORY);
     bind(Logger.class).to(LOGGER_FACTORY);
@@ -156,9 +156,10 @@
   }
 
   /**
-   * Adds a new scope. Maps a {@link Scope} instance to a given annotation.
+   * Binds a scope to an annotation.
    */
-  public void scope(Class<? extends Annotation> annotationType, Scope scope) {
+  public void bindScope(Class<? extends Annotation> annotationType,
+      Scope scope) {
     ensureNotCreated();
     Scope existing = scopes.get(nonNull(annotationType, "annotation type"));
     if (existing != null) {
@@ -175,7 +176,7 @@
    */
   public <T> BindingBuilder<T> bind(Key<T> key) {
     ensureNotCreated();
-    BindingBuilder<T> builder = new BindingBuilder<T>(key).from(source());
+    BindingBuilder<T> builder = new BindingBuilder<T>(key, source());
     bindingBuilders.add(builder);
     return builder;
   }
@@ -268,11 +269,11 @@
   }
 
   void addError(Object source, String message, Object... arguments) {
-    new ConfigurationErrorHandler(source).handle(message, arguments);
+    configurationErrorHandler.handle(source, message, arguments);
   }
 
   void addError(Object source, String message) {
-    new ConfigurationErrorHandler(source).handle(message);
+    configurationErrorHandler.handle(source, message);
   }
 
   /**
@@ -301,6 +302,7 @@
     Map<Key<?>, Binding<?>> bindings = new HashMap<Key<?>, Binding<?>>();
     container = new ContainerImpl(
         proxyFactoryBuilder.create(), bindings, scopes);
+    container.setErrorHandler(configurationErrorHandler);
 
     createConstantBindings();
 
@@ -484,8 +486,7 @@
    */
   public class BindingBuilder<T> {
 
-    Object source = ContainerBuilder.UNKNOWN_SOURCE;
-    ErrorHandler errorHandler = RuntimeErrorHandler.INSTANCE;
+    final Object source;
     Key<T> key;
     InternalFactory<? extends T> factory;
     TypeLiteral<? extends T> implementation;
@@ -493,8 +494,9 @@
     Scope scope;
     boolean preload = false;
 
-    BindingBuilder(Key<T> key) {
+    BindingBuilder(Key<T> key, Object source) {
       this.key = nonNull(key, "key");
+      this.source = source;
     }
 
     Object getSource() {
@@ -505,19 +507,13 @@
       return key;
     }
 
-    BindingBuilder<T> from(Object source) {
-      this.source = source;
-      this.errorHandler = new ConfigurationErrorHandler(source);
-      return this;
-    }
-
     /**
      * Specifies the annotation type for this binding.
      */
     public BindingBuilder<T> annotatedWith(
         Class<? extends Annotation> annotationType) {
       if (this.key.hasAnnotationType()) {
-        errorHandler.handle(ErrorMessages.ANNOTATION_ALREADY_SPECIFIED);
+        addError(source, ErrorMessages.ANNOTATION_ALREADY_SPECIFIED);
       } else {
         this.key = Key.get(this.key.getType(), annotationType);
       }
@@ -529,7 +525,7 @@
      */
     public BindingBuilder<T> annotatedWith(Annotation annotation) {
       if (this.key.hasAnnotationType()) {
-        errorHandler.handle(ErrorMessages.ANNOTATION_ALREADY_SPECIFIED);
+        addError(source, ErrorMessages.ANNOTATION_ALREADY_SPECIFIED);
       } else {
         this.key = Key.get(this.key.getType(), annotation);
       }
@@ -555,7 +551,7 @@
       ensureImplementationIsNotSet();
       this.implementation = implementation;
       final DefaultFactory<I> defaultFactory
-          = new DefaultFactory<I>(key, implementation, errorHandler);
+          = new DefaultFactory<I>(key, implementation, source);
       this.factory = defaultFactory;
       creationListeners.add(defaultFactory);
       return this;
@@ -578,7 +574,7 @@
       this.instance = nonNull(instance, "instance");
       this.factory = new ConstantFactory<T>(instance);
       if (this.scope != null) {
-        errorHandler.handle(ErrorMessages.SINGLE_INSTANCE_AND_SCOPE);
+        addError(source, ErrorMessages.SINGLE_INSTANCE_AND_SCOPE);
       }
       this.scope = CONTAINER;
       return this;
@@ -617,7 +613,7 @@
       ensureImplementationIsNotSet();
 
       final BoundFactory<T> boundFactory =
-          new BoundFactory<T>(factoryKey, errorHandler);
+          new BoundFactory<T>(factoryKey, source);
       creationListeners.add(boundFactory);
       this.factory = boundFactory;
 
@@ -629,13 +625,13 @@
      */
     private void ensureImplementationIsNotSet() {
       if (factory != null) {
-        errorHandler.handle(ErrorMessages.IMPLEMENTATION_ALREADY_SET);
+        addError(source, ErrorMessages.IMPLEMENTATION_ALREADY_SET);
       }
     }
 
     /**
      * Specifies the scope. References the annotation passed to {@link
-     * ContainerBuilder#scope(Class, Scope)}.
+     * ContainerBuilder#bindScope(Class, Scope)}.
      */
     public BindingBuilder<T> in(Class<? extends Annotation> scopeAnnotation) {
       ensureScopeNotSet();
@@ -644,7 +640,7 @@
       // is fine for now.
       this.scope = scopes.get(nonNull(scopeAnnotation, "scope annotation"));
       if (this.scope == null) {
-        errorHandler.handle(ErrorMessages.SCOPE_NOT_FOUND,
+        addError(source, ErrorMessages.SCOPE_NOT_FOUND,
             "@" + scopeAnnotation.getSimpleName());
       }
       return this;
@@ -662,12 +658,12 @@
     private void ensureScopeNotSet() {
       // Scoping isn't allowed when we have only one instance.
       if (this.instance != null) {
-        errorHandler.handle(ErrorMessages.SINGLE_INSTANCE_AND_SCOPE);
+        addError(source, ErrorMessages.SINGLE_INSTANCE_AND_SCOPE);
         return;
       }
 
       if (this.scope != null) {
-        errorHandler.handle(ErrorMessages.SCOPE_ALREADY_SET);
+        addError(source, ErrorMessages.SCOPE_ALREADY_SET);
       }
     }
 
@@ -695,7 +691,7 @@
       // Look for @Scoped on the implementation type.
       if (implementation != null) {
         Scope fromAnnotation = Scopes.getScopeForType(
-            implementation.getRawType(), scopes, errorHandler);
+            implementation.getRawType(), scopes, configurationErrorHandler);
         if (fromAnnotation != null) {
           if (this.scope == null) {
             this.scope = fromAnnotation;
@@ -721,18 +717,18 @@
       implements InternalFactory<T>, CreationListener {
 
     final Key<? extends Factory<? extends T>> factoryKey;
-    final ErrorHandler errorHandler;
+    final Object source;
     private InternalFactory<? extends Factory<? extends T>> factoryFactory;
 
     public BoundFactory(
         Key<? extends Factory<? extends T>> factoryKey,
-        ErrorHandler errorHandler) {
+        Object source) {
       this.factoryKey = factoryKey;
-      this.errorHandler = errorHandler;
+      this.source = source;
     }
 
     public void notify(final ContainerImpl container) {
-      container.withErrorHandler(errorHandler, new Runnable() {
+      container.withDefaultSource(source, new Runnable() {
         public void run() {
           factoryFactory = container.getInternalFactory(null, factoryKey);
         }
@@ -758,19 +754,19 @@
 
     private final TypeLiteral<T> implementation;
     private final Key<? super T> key;
-    private final ErrorHandler errorHandler;
+    private final Object source;
 
     ConstructorInjector<T> constructor;
 
     DefaultFactory(Key<? super T> key, TypeLiteral<T> implementation,
-        ErrorHandler errorHandler) {
+        Object source) {
       this.key = key;
       this.implementation = implementation;
-      this.errorHandler = errorHandler;
+      this.source = source;
     }
 
     public void notify(final ContainerImpl container) {
-      container.withErrorHandler(errorHandler, new Runnable() {
+      container.withDefaultSource(source, new Runnable() {
         public void run() {
           constructor = container.getConstructor(implementation);
         }
@@ -980,25 +976,12 @@
     }
   }
 
-  /**
-   * Handles errors up until we successfully create the container.
-   */
-  class ConfigurationErrorHandler extends AbstractErrorHandler {
+  ErrorHandler configurationErrorHandler = new AbstractErrorHandler() {
 
-    final Object source;
-
-    ConfigurationErrorHandler(Object source) {
-      this.source = source;
-    }
-
-    public void handle(String message) {
+    public void handle(Object source, String message) {
       add(new Message(source, message));
     }
-
-    public void handle(Throwable t) {
-      add(new Message(source, t.getMessage()));
-    }
-  }
+  };
 
   /**
    * Handles errors after the container is created.
@@ -1007,12 +990,8 @@
 
     static ErrorHandler INSTANCE = new RuntimeErrorHandler();
 
-    public void handle(String message) {
-      throw new ConfigurationException(message);
-    }
-
-    public void handle(Throwable t) {
-      throw new ConfigurationException(t);
+    public void handle(Object source, String message) {
+      throw new ConfigurationException("Error at " + source + " " + message);
     }
   }
 
@@ -1031,7 +1010,7 @@
     }
 
     void createInjectors(final ContainerImpl container) {
-      container.withErrorHandler(new ConfigurationErrorHandler(source),
+      container.withDefaultSource(source,
           new Runnable() {
             public void run() {
               for (Class<?> clazz : types) {
diff --git a/src/com/google/inject/ContainerImpl.java b/src/com/google/inject/ContainerImpl.java
index 3fffc3e..33ee60d 100644
--- a/src/com/google/inject/ContainerImpl.java
+++ b/src/com/google/inject/ContainerImpl.java
@@ -23,6 +23,7 @@
 import com.google.inject.util.ToStringBuilder;
 import com.google.inject.util.SurrogateAnnotations;
 import com.google.inject.util.DuplicateAnnotationException;
+import com.google.inject.util.StackTraceElements;
 
 import net.sf.cglib.reflect.FastClass;
 import net.sf.cglib.reflect.FastMethod;
@@ -91,6 +92,7 @@
   final Map<Class<? extends Annotation>, Scope> scopes;
 
   ErrorHandler errorHandler = new InvalidErrorHandler();
+  Object defaultSource = "[unknown source]";
 
   ContainerImpl(ConstructionProxyFactory constructionProxyFactory,
       Map<Key<?>, Binding<?>> bindings,
@@ -130,14 +132,17 @@
     return names;
   }
 
-  void withErrorHandler(ErrorHandler errorHandler, Runnable runnable) {
-    ErrorHandler previous = this.errorHandler;
-    this.errorHandler = errorHandler;
+  /**
+   * This is only used during container building.
+   */
+  void withDefaultSource(Object defaultSource, Runnable runnable) {
+    Object previous = this.defaultSource;
+    this.defaultSource = defaultSource;
     try {
       runnable.run();
     }
     finally {
-      this.errorHandler = previous;
+      this.defaultSource = previous;
     }
   }
 
@@ -213,8 +218,8 @@
           return new ConstantFactory<T>(t);
         }
         catch (ConstantConversionException e) {
-          errorHandler.handle(e);
-          return invalidFactory();
+          return handleConstantConversionError(
+              member, stringBinding, rawType, e);
         }
       }
 
@@ -225,8 +230,8 @@
           t = (T) Enum.valueOf((Class) rawType, value);
         }
         catch (IllegalArgumentException e) {
-          errorHandler.handle(createMessage(value, key, member, e.toString()));
-          return invalidFactory();
+          return handleConstantConversionError(
+              member, stringBinding, rawType, e);
         }
         return new ConstantFactory<T>(t);
       }
@@ -238,8 +243,8 @@
           return new ConstantFactory<T>((T) Class.forName(value));
         }
         catch (ClassNotFoundException e) {
-          errorHandler.handle(createMessage(value, key, member, e.toString()));
-          return invalidFactory();
+          return handleConstantConversionError(
+              member, stringBinding, rawType, e);
         }
       }
     }
@@ -257,12 +262,9 @@
       // If we're injecting into a member, include it in the error messages.
       final ErrorHandler previous = this.errorHandler;
       this.errorHandler = new AbstractErrorHandler() {
-        public void handle(String message) {
-          previous.handle("Error while injecting "
-              + ErrorMessages.convert(member) + ": " + message);
-        }
-        public void handle(Throwable t) {
-          previous.handle(t);
+        public void handle(Object source, String message) {
+          previous.handle(source, "Error while injecting at "
+              + StackTraceElements.forMember(member) + ": " + message);
         }
       };
       try {
@@ -275,6 +277,18 @@
     return (InternalFactory<? extends T>) getImplicitBinding(rawType);
   }
 
+  private <T> InternalFactory<T> handleConstantConversionError(
+      Member member, Binding<String> stringBinding, Class<?> rawType,
+      Exception e) {
+    errorHandler.handle(
+        StackTraceElements.forMember(member),
+        ErrorMessages.CONSTANT_CONVERSION_ERROR,
+        stringBinding.getSource(),
+        rawType,
+        e.getMessage());
+    return invalidFactory();
+  }
+
   boolean isConstantType(Class<?> type) {
     return PRIMITIVE_CONVERTERS.containsKey(type)
         || Enum.class.isAssignableFrom(type)
@@ -287,11 +301,6 @@
   final Map<Class<?>, List<Injector>> injectors
       = new ReferenceCache<Class<?>, List<Injector>>() {
     protected List<Injector> create(Class<?> key) {
-      if (key.isInterface()) {
-        errorHandler.handle(ErrorMessages.CANNOT_INJECT_INTERFACE, key);
-        return Collections.emptyList();
-      }
-
       List<Injector> injectors = new ArrayList<Injector>();
       addInjectors(key, injectors);
       return injectors;
@@ -342,15 +351,7 @@
       InjectorFactory<M> injectorFactory) {
     for (M member : members) {
       if (isStatic(member) == statics) {
-        Inject inject = null;
-        try {
-          inject = SurrogateAnnotations.findAnnotation(Inject.class, member);
-        } catch (DuplicateAnnotationException e) {
-          errorHandler.handle(ErrorMessages.DUPLICATE_ANNOTATIONS,
-              Inject.class.getSimpleName(), member, e.getFirst(),
-              e.getSecond());
-        }
-
+        Inject inject = member.getAnnotation(Inject.class);
         if (inject != null) {
           try {
             injectors.add(injectorFactory.create(this, member));
@@ -525,7 +526,7 @@
     @SuppressWarnings("unchecked")
     protected ConstructorInjector<?> create(Class<?> implementation) {
       if (implementation.isInterface()) {
-        errorHandler.handle(
+        errorHandler.handle(defaultSource,
             ErrorMessages.CANNOT_INJECT_INTERFACE, implementation);
         return ConstructorInjector.invalidConstructor();
       }
diff --git a/src/com/google/inject/ErrorHandler.java b/src/com/google/inject/ErrorHandler.java
index a082210..0423a4b 100644
--- a/src/com/google/inject/ErrorHandler.java
+++ b/src/com/google/inject/ErrorHandler.java
@@ -26,15 +26,10 @@
   /**
    * Handles an error.
    */
-  void handle(String message);
+  void handle(Object source, String message);
 
   /**
    * Handles an error.
    */
-  void handle(String message, Object... arguments);
-
-  /**
-   * Handles an error.
-   */
-  void handle(Throwable t);
+  void handle(Object source, String message, Object... arguments);
 }
diff --git a/src/com/google/inject/ErrorMessages.java b/src/com/google/inject/ErrorMessages.java
index 7f536f9..958b173 100644
--- a/src/com/google/inject/ErrorMessages.java
+++ b/src/com/google/inject/ErrorMessages.java
@@ -23,6 +23,7 @@
 import java.util.List;
 import java.util.Collection;
 import java.util.Arrays;
+import com.google.inject.util.StackTraceElements;
 
 /**
  * Error message templates.
@@ -32,24 +33,28 @@
 class ErrorMessages {
 
   private static final String MISSING_BINDING =
-      "Binding to %s not found, but %s requires it. No bindings to that"
+      "Binding to %s not found. No bindings to that"
           + " type were found.";
 
   private static final String MISSING_BINDING_BUT_OTHERS_EXIST =
-      "Binding to %s not found, but %s requires it. Annotations on other"
+      "Binding to %s not found. Annotations on other"
           + " bindings to that type include: %s";
 
   static void handleMissingBinding(ErrorHandler errorHandler, Member member,
       Key<?> key, List<String> otherNames) {
     if (otherNames.isEmpty()) {
-      errorHandler.handle(MISSING_BINDING, key, member);
+      errorHandler.handle(StackTraceElements.forMember(member),
+          MISSING_BINDING, key);
     }
     else {
-      errorHandler.handle(
-          MISSING_BINDING_BUT_OTHERS_EXIST, key, member, otherNames);
+      errorHandler.handle(StackTraceElements.forMember(member),
+          MISSING_BINDING_BUT_OTHERS_EXIST, key, otherNames);
     }
   }
 
+  static final String CONSTANT_CONVERSION_ERROR = "Error converting String"
+      + " constant bound at %s to %s: %s";
+
   static final String CANNOT_BIND_TO_LOCATOR = "Binding to Locator<?> is not"
       + " allowed.";
 
@@ -65,8 +70,8 @@
   static final String MISSING_CONSTRUCTOR = "Could not find a suitable"
       + " constructor in %s. " + CONSTRUCTOR_RULES;
 
-  static final String TOO_MANY_CONSTRUCTORS = "More than one constructor"
-      + " annotated with @Inject found in %s. " + CONSTRUCTOR_RULES;
+  static final String TOO_MANY_CONSTRUCTORS = "Found more than one constructor"
+      + " annotated with @Inject. " + CONSTRUCTOR_RULES;
 
   static final String DUPLICATE_SCOPES = "Scope %s is already bound to %s."
       + " Cannot bind %s.";
@@ -90,11 +95,11 @@
 
   static final String SCOPE_ALREADY_SET = "Scope is set more than once.";
 
-  static final String DUPLICATE_ANNOTATIONS = "Duplicate binding annotations"
-      + " found on %s: %s and %s";
+  static final String DUPLICATE_ANNOTATIONS = "Found more than one annotation"
+      + " annotated with @Binder: %s and %s";
 
-  public static final String DUPLICATE_SCOPE_ANNOTATIONS = "Duplicate scope"
-      + " annotations found on %s: %s and %s";
+  public static final String DUPLICATE_SCOPE_ANNOTATIONS = "More than one scope"
+      + " annotation was found: %s and %s";
 
   static final String CONSTANT_VALUE_ALREADY_SET = "Constant value is set more"
       + " than once.";
diff --git a/src/com/google/inject/InvalidErrorHandler.java b/src/com/google/inject/InvalidErrorHandler.java
index 1f88c4b..4d7e180 100644
--- a/src/com/google/inject/InvalidErrorHandler.java
+++ b/src/com/google/inject/InvalidErrorHandler.java
@@ -23,11 +23,7 @@
 
   static ErrorHandler INSTANCE = new InvalidErrorHandler();
 
-  public void handle(String message) {
+  public void handle(Object source, String message) {
     throw new AssertionError(message);
   }
-
-  public void handle(Throwable t) {
-    throw new AssertionError(t);
-  }
 }
diff --git a/src/com/google/inject/Key.java b/src/com/google/inject/Key.java
index 9f80fa5..9865e9a 100644
--- a/src/com/google/inject/Key.java
+++ b/src/com/google/inject/Key.java
@@ -18,6 +18,7 @@
 
 import static com.google.inject.util.Objects.nonNull;
 import com.google.inject.util.ToStringBuilder;
+import com.google.inject.util.StackTraceElements;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Member;
 import java.lang.reflect.Type;
@@ -276,8 +277,8 @@
         if (found == null) {
           found = annotation;
         } else {
-          errorHandler.handle(ErrorMessages.DUPLICATE_ANNOTATIONS, member,
-              found, annotation);
+          errorHandler.handle(StackTraceElements.forMember(member),
+              ErrorMessages.DUPLICATE_ANNOTATIONS, found, annotation);
         }
       }
     }
diff --git a/src/com/google/inject/Scopes.java b/src/com/google/inject/Scopes.java
index 755e9d9..41d814b 100644
--- a/src/com/google/inject/Scopes.java
+++ b/src/com/google/inject/Scopes.java
@@ -18,6 +18,7 @@
 
 import java.lang.annotation.Annotation;
 import java.util.Map;
+import com.google.inject.util.StackTraceElements;
 
 /**
  * Built in scope implementations.
@@ -96,8 +97,8 @@
       Scope scope = scopes.get(annotation.annotationType());
       if (scope != null) {
         if (found != null) {
-          errorHandler.handle(ErrorMessages.DUPLICATE_SCOPE_ANNOTATIONS,
-              implementation, found, scope);
+          errorHandler.handle(StackTraceElements.forType(implementation),
+              ErrorMessages.DUPLICATE_SCOPE_ANNOTATIONS, found, scope);
         } else {
           found = scope;
         }
diff --git a/src/com/google/inject/util/StackTraceElements.java b/src/com/google/inject/util/StackTraceElements.java
new file mode 100644
index 0000000..d1929c8
--- /dev/null
+++ b/src/com/google/inject/util/StackTraceElements.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (C) 2006 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.inject.util;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Member;
+import java.util.Map;
+import java.io.IOException;
+import static com.google.inject.util.ReferenceType.*;
+
+/**
+ * Creates stack trace elements for members.
+ *
+ * @author crazybob@google.com (Bob Lee)
+ */
+public class StackTraceElements {
+
+  static final Map<Class<?>, LineNumbers> lineNumbersCache
+      = new ReferenceCache<Class<?>, LineNumbers>(WEAK, SOFT) {
+    protected LineNumbers create(Class<?> key) {
+      try {
+        return new LineNumbers(key);
+      }
+      catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+    }
+  };
+
+  public static Object forMember(Member member) {
+    if (member == null) {
+      return "[unknown source]";  
+    }
+
+    Class declaringClass = member.getDeclaringClass();
+    LineNumbers lineNumbers = lineNumbersCache.get(declaringClass);
+    Integer lineNumber = lineNumbers.getLineNumber(member);
+    StackTraceElement element = new StackTraceElement(
+      declaringClass.getName(), member.getName(), lineNumbers.getSource(),
+        lineNumber == null ? 0 : lineNumber);
+    return element;
+  }
+
+  public static Object forType(Class<?> implementation) {
+    LineNumbers lineNumbers = lineNumbersCache.get(implementation);
+    return new StackTraceElement(
+        implementation.getName(), "<init>", lineNumbers.getSource(), 0);
+  }
+}