blob: 3c1837cb17500e9a8c404597b78d3df8b12a0d30 [file] [log] [blame]
Christian Edward Gruber605bd082013-08-09 11:04:00 -07001package com.google.inject.spi;
2
3import com.google.common.base.Preconditions;
4import com.google.common.collect.ImmutableList;
5import com.google.inject.internal.util.StackTraceElements;
6import com.google.inject.internal.util.StackTraceElements.InMemoryStackTraceElement;
7
8import java.util.List;
9
10/**
Sam Berlin6b3086d2014-07-20 13:03:09 -040011 * Contains information about where and how an {@link Element element} was
12 * bound.
Christian Edward Gruber605bd082013-08-09 11:04:00 -070013 * <p>
Sam Berlin6b3086d2014-07-20 13:03:09 -040014 * The {@link #getDeclaringSource() declaring source} refers to a location in
15 * source code that defines the Guice {@link Element element}. For example, if
16 * the element is created from a method annotated by {@literal @Provides}, the
17 * declaring source of element would be the method itself.
Christian Edward Gruber605bd082013-08-09 11:04:00 -070018 * <p>
Sam Berlin6b3086d2014-07-20 13:03:09 -040019 * The {@link #getStackTrace()} refers to the sequence of calls ends at one of
20 * {@link com.google.inject.Binder} {@code bindXXX()} methods and eventually
21 * defines the element. Note that {@link #getStackTrace()} lists
22 * {@link StackTraceElement StackTraceElements} in reverse chronological order.
23 * The first element (index zero) is the last method call and the last element
24 * is the first method invocation. By default, the stack trace is not collected.
25 * The default behavior can be changed by setting the
26 * {@code guice_include_stack_traces} flag value. The value can be either
27 * {@code OFF}, {@code ONLY_FOR_DECLARING_SOURCE} or {@code COMPLETE}. Note that
28 * collecting stack traces for every binding can cause a performance hit when
29 * the injector is created.
Christian Edward Gruber605bd082013-08-09 11:04:00 -070030 * <p>
Sam Berlin6b3086d2014-07-20 13:03:09 -040031 * The sequence of class names of {@link com.google.inject.Module modules}
32 * involved in the element creation can be retrieved by
33 * {@link #getModuleClassNames()}. Similar to {@link #getStackTrace()}, the
34 * order is reverse chronological. The first module (index 0) is the module that
35 * installs the {@link Element element}. The last module is the root module.
36 * <p>
37 * In order to support the cases where a Guice {@link Element element} is
38 * created from another Guice {@link Element element} (original) (e.g., by
39 * {@link Element#applyTo}), it also provides a reference to the original
40 * element source ({@link #getOriginalElementSource()}).
Christian Edward Gruber605bd082013-08-09 11:04:00 -070041 */
42public final class ElementSource {
43
44 /**
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -070045 * The {@link ElementSource source} of element that this element created from (if there is any),
Christian Edward Gruber605bd082013-08-09 11:04:00 -070046 * otherwise {@code null}.
47 */
48 final ElementSource originalElementSource;
49
50 /** The {@link ModuleSource source} of module creates the element. */
51 final ModuleSource moduleSource;
52
53 /**
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -070054 * The partial call stack that starts at the last module {@link Module#Configure(Binder)
55 * configure(Binder)} call. The value is empty if stack trace collection is off.
Christian Edward Gruber605bd082013-08-09 11:04:00 -070056 */
57 final InMemoryStackTraceElement[] partialCallStack;
58
59 /**
60 * Refers to a single location in source code that causes the element creation. It can be any
61 * object such as {@link Constructor}, {@link Method}, {@link Field}, {@link StackTraceElement},
62 * etc. For example, if the element is created from a method annotated by {@literal @Provides},
63 * the declaring source of element would be the method itself.
64 */
65 final Object declaringSource;
66
67 /**
68 * Creates a new {@ElementSource} from the given parameters.
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -070069 * @param originalElementSource The source of element that this element created from (if there is
Christian Edward Gruber605bd082013-08-09 11:04:00 -070070 * any), otherwise {@code null}.
71 * @param declaringSource the source (in)directly declared the element.
72 * @param moduleSource the moduleSource when the element is bound
73 * @param partialCallStack the partial call stack from the top module to where the element is
74 * bound
75 */
76 ElementSource(/* @Nullable */ ElementSource originalSource, Object declaringSource,
77 ModuleSource moduleSource, StackTraceElement[] partialCallStack) {
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -070078 Preconditions.checkNotNull(declaringSource, "declaringSource cannot be null.");
Christian Edward Gruber605bd082013-08-09 11:04:00 -070079 Preconditions.checkNotNull(moduleSource, "moduleSource cannot be null.");
80 Preconditions.checkNotNull(partialCallStack, "partialCallStack cannot be null.");
Christian Edward Gruber605bd082013-08-09 11:04:00 -070081 this.originalElementSource = originalSource;
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -070082 this.declaringSource = declaringSource;
Christian Edward Gruber605bd082013-08-09 11:04:00 -070083 this.moduleSource = moduleSource;
84 this.partialCallStack = StackTraceElements.convertToInMemoryStackTraceElement(partialCallStack);
Christian Edward Gruber605bd082013-08-09 11:04:00 -070085 }
86
87 /**
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -070088 * Returns the {@link ElementSource} of the element this was created or copied from. If this was
Christian Edward Gruber605bd082013-08-09 11:04:00 -070089 * not created or copied from another element, returns {@code null}.
90 */
91 public ElementSource getOriginalElementSource() {
92 return originalElementSource;
93 }
94
95 /**
96 * Returns a single location in source code that defines the element. It can be any object
Sam Berlin6b3086d2014-07-20 13:03:09 -040097 * such as {@link java.lang.reflect.Constructor}, {@link java.lang.reflect.Method},
98 * {@link java.lang.reflect.Field}, {@link StackTraceElement}, etc. For
99 * example, if the element is created from a method annotated by {@literal @Provides}, the
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700100 * declaring source of element would be the method itself.
101 */
102 public Object getDeclaringSource() {
103 return declaringSource;
104 }
105
106 /**
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700107 * Returns the class names of modules involved in creating this {@link Element}. The first
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700108 * element (index 0) is the class name of module that defined the element, and the last element
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700109 * is the class name of root module.
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700110 */
111 public List<String> getModuleClassNames() {
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700112 return moduleSource.getModuleClassNames();
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700113 }
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700114
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700115 /**
Sam Berlin6b3086d2014-07-20 13:03:09 -0400116 * Returns the position of {@link com.google.inject.Module#configure configure(Binder)} method
117 * call in the {@link #getStackTrace stack trace} for modules that their classes returned by
118 * {@link #getModuleClassNames}. For example, if the stack trace looks like the following:
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700119 * <p>
120 * {@code
121 * 0 - Binder.bind(),
122 * 1 - ModuleTwo.configure(),
123 * 2 - Binder.install(),
124 * 3 - ModuleOne.configure(),
125 * 4 - theRest().
126 * }
127 * <p>
Christian Edward Gruber2bb47712013-09-18 10:56:54 -0700128 * 1 and 3 are returned.
129 * <p>
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700130 * In the cases where stack trace is not available (i.e., the stack trace was not collected),
131 * it returns -1 for all module positions.
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700132 */
133 public List<Integer> getModuleConfigurePositionsInStackTrace() {
134 int size = moduleSource.size();
135 Integer[] positions = new Integer[size];
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700136 int chunkSize = partialCallStack.length;
137 positions[0] = chunkSize - 1;
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700138 ModuleSource current = moduleSource;
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700139 for (int cursor = 1; cursor < size; cursor++) {
140 chunkSize = current.getPartialCallStackSize();
141 positions[cursor] = positions[cursor - 1] + chunkSize;
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700142 current = current.getParent();
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700143 }
144 return ImmutableList.<Integer>copyOf(positions);
145 }
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700146
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700147 /**
Sam Berlin6b3086d2014-07-20 13:03:09 -0400148 * Returns the sequence of method calls that ends at one of {@link com.google.inject.Binder}
149 * {@code bindXXX()} methods and eventually defines the element. Note that
150 * {@link #getStackTrace} lists {@link StackTraceElement StackTraceElements} in reverse
151 * chronological order. The first element (index zero) is the last method call and the last
152 * element is the first method invocation. In the cases where stack trace is not available
153 * (i.e.,the stack trace was not collected), it returns an empty array.
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700154 */
155 public StackTraceElement[] getStackTrace() {
156 int modulesCallStackSize = moduleSource.getStackTraceSize();
157 int chunkSize = partialCallStack.length;
Christian Edward Gruberba5acdf2013-10-05 14:05:39 -0700158 int size = moduleSource.getStackTraceSize() + chunkSize;
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700159 StackTraceElement[] callStack = new StackTraceElement[size];
160 System.arraycopy(
161 StackTraceElements.convertToStackTraceElement(partialCallStack), 0, callStack, 0,
162 chunkSize);
163 System.arraycopy(moduleSource.getStackTrace(), 0, callStack, chunkSize, modulesCallStackSize);
164 return callStack;
165 }
Christian Edward Gruber2bb47712013-09-18 10:56:54 -0700166
167 /**
Christian Edward Gruber605bd082013-08-09 11:04:00 -0700168 * Returns {@code getDeclaringSource().toString()} value.
169 */
170 @Override
171 public String toString() {
172 return getDeclaringSource().toString();
173 }
174}