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);
+ }
+}