Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 1 | package com.google.inject.spi; |
| 2 | |
| 3 | import com.google.common.base.Preconditions; |
| 4 | import com.google.common.collect.ImmutableList; |
| 5 | import com.google.inject.internal.util.StackTraceElements; |
| 6 | import com.google.inject.internal.util.StackTraceElements.InMemoryStackTraceElement; |
| 7 | |
| 8 | import java.util.List; |
| 9 | |
| 10 | /** |
Sam Berlin | 6b3086d | 2014-07-20 13:03:09 -0400 | [diff] [blame^] | 11 | * Contains information about where and how an {@link Element element} was |
| 12 | * bound. |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 13 | * <p> |
Sam Berlin | 6b3086d | 2014-07-20 13:03:09 -0400 | [diff] [blame^] | 14 | * 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 Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 18 | * <p> |
Sam Berlin | 6b3086d | 2014-07-20 13:03:09 -0400 | [diff] [blame^] | 19 | * 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 Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 30 | * <p> |
Sam Berlin | 6b3086d | 2014-07-20 13:03:09 -0400 | [diff] [blame^] | 31 | * 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 Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 41 | */ |
| 42 | public final class ElementSource { |
| 43 | |
| 44 | /** |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame] | 45 | * The {@link ElementSource source} of element that this element created from (if there is any), |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 46 | * 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 Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame] | 54 | * 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 Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 56 | */ |
| 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 Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame] | 69 | * @param originalElementSource The source of element that this element created from (if there is |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 70 | * 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 Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame] | 78 | Preconditions.checkNotNull(declaringSource, "declaringSource cannot be null."); |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 79 | Preconditions.checkNotNull(moduleSource, "moduleSource cannot be null."); |
| 80 | Preconditions.checkNotNull(partialCallStack, "partialCallStack cannot be null."); |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 81 | this.originalElementSource = originalSource; |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame] | 82 | this.declaringSource = declaringSource; |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 83 | this.moduleSource = moduleSource; |
| 84 | this.partialCallStack = StackTraceElements.convertToInMemoryStackTraceElement(partialCallStack); |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 85 | } |
| 86 | |
| 87 | /** |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame] | 88 | * Returns the {@link ElementSource} of the element this was created or copied from. If this was |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 89 | * 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 Berlin | 6b3086d | 2014-07-20 13:03:09 -0400 | [diff] [blame^] | 97 | * 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 Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 100 | * declaring source of element would be the method itself. |
| 101 | */ |
| 102 | public Object getDeclaringSource() { |
| 103 | return declaringSource; |
| 104 | } |
| 105 | |
| 106 | /** |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame] | 107 | * Returns the class names of modules involved in creating this {@link Element}. The first |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 108 | * element (index 0) is the class name of module that defined the element, and the last element |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame] | 109 | * is the class name of root module. |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 110 | */ |
| 111 | public List<String> getModuleClassNames() { |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame] | 112 | return moduleSource.getModuleClassNames(); |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 113 | } |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame] | 114 | |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 115 | /** |
Sam Berlin | 6b3086d | 2014-07-20 13:03:09 -0400 | [diff] [blame^] | 116 | * 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 Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 119 | * <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 Gruber | 2bb4771 | 2013-09-18 10:56:54 -0700 | [diff] [blame] | 128 | * 1 and 3 are returned. |
| 129 | * <p> |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame] | 130 | * 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 Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 132 | */ |
| 133 | public List<Integer> getModuleConfigurePositionsInStackTrace() { |
| 134 | int size = moduleSource.size(); |
| 135 | Integer[] positions = new Integer[size]; |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame] | 136 | int chunkSize = partialCallStack.length; |
| 137 | positions[0] = chunkSize - 1; |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 138 | ModuleSource current = moduleSource; |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame] | 139 | for (int cursor = 1; cursor < size; cursor++) { |
| 140 | chunkSize = current.getPartialCallStackSize(); |
| 141 | positions[cursor] = positions[cursor - 1] + chunkSize; |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 142 | current = current.getParent(); |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 143 | } |
| 144 | return ImmutableList.<Integer>copyOf(positions); |
| 145 | } |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame] | 146 | |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 147 | /** |
Sam Berlin | 6b3086d | 2014-07-20 13:03:09 -0400 | [diff] [blame^] | 148 | * 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 Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 154 | */ |
| 155 | public StackTraceElement[] getStackTrace() { |
| 156 | int modulesCallStackSize = moduleSource.getStackTraceSize(); |
| 157 | int chunkSize = partialCallStack.length; |
Christian Edward Gruber | ba5acdf | 2013-10-05 14:05:39 -0700 | [diff] [blame] | 158 | int size = moduleSource.getStackTraceSize() + chunkSize; |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 159 | 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 Gruber | 2bb4771 | 2013-09-18 10:56:54 -0700 | [diff] [blame] | 166 | |
| 167 | /** |
Christian Edward Gruber | 605bd08 | 2013-08-09 11:04:00 -0700 | [diff] [blame] | 168 | * Returns {@code getDeclaringSource().toString()} value. |
| 169 | */ |
| 170 | @Override |
| 171 | public String toString() { |
| 172 | return getDeclaringSource().toString(); |
| 173 | } |
| 174 | } |