blob: 627ff4d415c44d4bafa9b8e3d56ef5231c5b4569 [file] [log] [blame]
package com.google.inject.spi;
import com.google.common.base.Preconditions;
import com.google.inject.Module;
import com.google.inject.internal.util.StackTraceElements;
import com.google.inject.internal.util.StackTraceElements.InMemoryStackTraceElement;
/**
* Associated to a {@link Module module}, provides the module class name, the parent module {@link
* ModuleSource source}, and the call stack that ends just before the module {@link
* Module#configure(Binder) configure(Binder)} method invocation.
*/
final class ModuleSource {
/**
* The class name of module that this {@link ModuleSource} associated to. This value is null when
* the module class {@link Class#getName() getName()} returns null.
*/
private final String moduleClassName;
/**
* The parent {@link ModuleSource module source}.
*/
private final ModuleSource parent;
/**
* The chunk of call stack that starts from the parent module {@link Module#configure(Binder)
* configure(Binder)} call and ends just before the module {@link Module#configure(Binder)
* configure(Binder)} method invocation. For a module without a parent module the chunk starts
* from the bottom of call stack.
*/
private final InMemoryStackTraceElement[] partialCallStack;
/**
* Creates a new {@link ModuleSource} with a {@literal null} parent.
* @param module the corresponding module
* @param partialCallStack the chunk of call stack that starts from the parent module {@link
* Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
* Module#configure(Binder) configure(Binder)} method invocation
*/
ModuleSource(Module module, StackTraceElement[] partialCallStack) {
this(null, module, partialCallStack);
}
/**
* Creates a new {@link ModuleSource} Object.
* @param parent the parent module {@link ModuleSource source}
* @param module the corresponding module
* @param partialCallStack the chunk of call stack that starts from the parent module {@link
* Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
* Module#configure(Binder) configure(Binder)} method invocation
*/
private ModuleSource(
/* @Nullable */ ModuleSource parent, Module module, StackTraceElement[] partialCallStack) {
Preconditions.checkNotNull(module, "module cannot be null.");
Preconditions.checkNotNull(partialCallStack, "partialCallStack cannot be null.");
this.parent = parent;
this.moduleClassName = module.getClass().getName();
this.partialCallStack = StackTraceElements.convertToInMemoryStackTraceElement(partialCallStack);
}
/**
* Returns the corresponding module class name. The value can be null.
*
* @see Class#getName()
*/
String getModuleClassName() {
return moduleClassName;
}
/**
* Returns the chunk of call stack that starts from the parent module {@link
* Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
* Module#configure(Binder) configure(Binder)} method invocation
*/
StackTraceElement[] getPartialCallStack() {
return StackTraceElements.convertToStackTraceElement(partialCallStack);
}
/**
* Returns the size of partial call stack.
*/
int getPartialCallStackSize() {
return partialCallStack.length;
}
/**
* Creates and returns a child {@link ModuleSource} corresponding to the {@link Module module}.
* @param module the corresponding module
* @param partialCallStack the chunk of call stack that starts from the parent module {@link
* Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
* Module#configure(Binder) configure(Binder)} method invocation
*/
ModuleSource createChild(Module module, StackTraceElement[] partialCallStack) {
return new ModuleSource(this, module, partialCallStack);
}
/**
* Returns the parent module {@link ModuleSource source}.
*/
ModuleSource getParent() {
return parent;
}
/**
* Returns the size of {@link ModuleSource ModuleSources} chain (all parents) that ends at this
* object.
*/
int size() {
if (parent == null) {
return 1;
}
return parent.size() + 1;
}
/**
* Returns the size of call stack that ends just before the module {@link Module#configure(Binder)
* configure(Binder)} method invocation (see {@link #getStackTrace()}).
*/
int getStackTraceSize() {
if (parent == null) {
return partialCallStack.length;
}
return parent.getStackTraceSize() + partialCallStack.length;
}
/**
* Returns the full call stack that ends just before the module {@link Module#configure(Binder)
* configure(Binder)} method invocation.
*/
StackTraceElement[] getStackTrace() {
StackTraceElement[] callStack = new StackTraceElement[getStackTraceSize()];
int cursor = 0; // Index 0 stores the top Module.configure()
ModuleSource current = this;
while (current != null) {
StackTraceElement[] chunk =
StackTraceElements.convertToStackTraceElement(current.partialCallStack);
int chunkSize = chunk.length;
System.arraycopy(chunk, 0, callStack, cursor, chunkSize);
current = current.parent;
cursor = cursor + chunkSize;
}
return callStack;
}
}