• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.inject.spi;
18 
19 import com.google.common.base.Preconditions;
20 import com.google.common.collect.ImmutableList;
21 import com.google.inject.internal.util.StackTraceElements;
22 import com.google.inject.internal.util.StackTraceElements.InMemoryStackTraceElement;
23 import java.util.List;
24 
25 /**
26  * Contains information about where and how an {@link Element element} was bound.
27  *
28  * <p>The {@link #getDeclaringSource() declaring source} refers to a location in source code that
29  * defines the Guice {@link Element element}. For example, if the element is created from a method
30  * annotated by {@literal @Provides}, the declaring source of element would be the method itself.
31  *
32  * <p>The {@link #getStackTrace()} refers to the sequence of calls ends at one of {@link
33  * com.google.inject.Binder} {@code bindXXX()} methods and eventually defines the element. Note that
34  * {@link #getStackTrace()} lists {@link StackTraceElement StackTraceElements} in reverse
35  * chronological order. The first element (index zero) is the last method call and the last element
36  * is the first method invocation. By default, the stack trace is not collected. The default
37  * behavior can be changed by setting the {@code guice_include_stack_traces} flag value. The value
38  * can be either {@code OFF}, {@code ONLY_FOR_DECLARING_SOURCE} or {@code COMPLETE}. Note that
39  * collecting stack traces for every binding can cause a performance hit when the injector is
40  * created.
41  *
42  * <p>The sequence of class names of {@link com.google.inject.Module modules} involved in the
43  * element creation can be retrieved by {@link #getModuleClassNames()}. Similar to {@link
44  * #getStackTrace()}, the order is reverse chronological. The first module (index 0) is the module
45  * that installs the {@link Element element}. The last module is the root module.
46  *
47  * <p>In order to support the cases where a Guice {@link Element element} is created from another
48  * Guice {@link Element element} (original) (e.g., by {@link Element#applyTo}), it also provides a
49  * reference to the original element source ({@link #getOriginalElementSource()}).
50  *
51  * @since 4.0
52  */
53 public final class ElementSource {
54 
55   /**
56    * The {@link ElementSource source} of element that this element created from (if there is any),
57    * otherwise {@code null}.
58    */
59   final ElementSource originalElementSource;
60 
61   /** The {@link ModuleSource source} of module creates the element. */
62   final ModuleSource moduleSource;
63 
64   /**
65    * The partial call stack that starts at the last module {@link Module#Configure(Binder)
66    * configure(Binder)} call. The value is empty if stack trace collection is off.
67    */
68   final InMemoryStackTraceElement[] partialCallStack;
69 
70   /**
71    * Refers to a single location in source code that causes the element creation. It can be any
72    * object such as {@link Constructor}, {@link Method}, {@link Field}, {@link StackTraceElement},
73    * etc. For example, if the element is created from a method annotated by {@literal @Provides},
74    * the declaring source of element would be the method itself.
75    */
76   final Object declaringSource;
77 
78   /**
79    * Creates a new {@ElementSource} from the given parameters.
80    *
81    * @param originalElementSource The source of element that this element created from (if there is
82    *     any), otherwise {@code null}.
83    * @param declaringSource the source (in)directly declared the element.
84    * @param moduleSource the moduleSource when the element is bound
85    * @param partialCallStack the partial call stack from the top module to where the element is
86    *     bound
87    */
ElementSource( ElementSource originalSource, Object declaringSource, ModuleSource moduleSource, StackTraceElement[] partialCallStack)88   ElementSource(
89       /* @Nullable */ ElementSource originalSource,
90       Object declaringSource,
91       ModuleSource moduleSource,
92       StackTraceElement[] partialCallStack) {
93     Preconditions.checkNotNull(declaringSource, "declaringSource cannot be null.");
94     Preconditions.checkNotNull(moduleSource, "moduleSource cannot be null.");
95     Preconditions.checkNotNull(partialCallStack, "partialCallStack cannot be null.");
96     this.originalElementSource = originalSource;
97     this.declaringSource = declaringSource;
98     this.moduleSource = moduleSource;
99     this.partialCallStack = StackTraceElements.convertToInMemoryStackTraceElement(partialCallStack);
100   }
101 
102   /**
103    * Returns the {@link ElementSource} of the element this was created or copied from. If this was
104    * not created or copied from another element, returns {@code null}.
105    */
getOriginalElementSource()106   public ElementSource getOriginalElementSource() {
107     return originalElementSource;
108   }
109 
110   /**
111    * Returns a single location in source code that defines the element. It can be any object such as
112    * {@link java.lang.reflect.Constructor}, {@link java.lang.reflect.Method}, {@link
113    * java.lang.reflect.Field}, {@link StackTraceElement}, etc. For example, if the element is
114    * created from a method annotated by {@literal @Provides}, the declaring source of element would
115    * be the method itself.
116    */
getDeclaringSource()117   public Object getDeclaringSource() {
118     return declaringSource;
119   }
120 
121   /**
122    * Returns the class names of modules involved in creating this {@link Element}. The first element
123    * (index 0) is the class name of module that defined the element, and the last element is the
124    * class name of root module.
125    */
getModuleClassNames()126   public List<String> getModuleClassNames() {
127     return moduleSource.getModuleClassNames();
128   }
129 
130   /**
131    * Returns the position of {@link com.google.inject.Module#configure configure(Binder)} method
132    * call in the {@link #getStackTrace stack trace} for modules that their classes returned by
133    * {@link #getModuleClassNames}. For example, if the stack trace looks like the following:
134    *
135    * <ol>
136    *   <li>{@code Binder.bind()}
137    *   <li>{@code ModuleTwo.configure()}
138    *   <li>{@code Binder.install()}
139    *   <li>{@code ModuleOne.configure()}
140    *   <li>{@code theRest().
141    * </ol>
142    *
143    * <p>1 and 3 are returned.
144    *
145    * <p>In the cases where stack trace is not available (i.e., the stack trace was not collected),
146    * it returns -1 for all module positions.
147    */
getModuleConfigurePositionsInStackTrace()148   public List<Integer> getModuleConfigurePositionsInStackTrace() {
149     int size = moduleSource.size();
150     Integer[] positions = new Integer[size];
151     int chunkSize = partialCallStack.length;
152     positions[0] = chunkSize - 1;
153     ModuleSource current = moduleSource;
154     for (int cursor = 1; cursor < size; cursor++) {
155       chunkSize = current.getPartialCallStackSize();
156       positions[cursor] = positions[cursor - 1] + chunkSize;
157       current = current.getParent();
158     }
159     return ImmutableList.<Integer>copyOf(positions);
160   }
161 
162   /**
163    * Returns the sequence of method calls that ends at one of {@link com.google.inject.Binder}
164    * {@code bindXXX()} methods and eventually defines the element. Note that {@link #getStackTrace}
165    * lists {@link StackTraceElement StackTraceElements} in reverse chronological order. The first
166    * element (index zero) is the last method call and the last element is the first method
167    * invocation. In the cases where stack trace is not available (i.e.,the stack trace was not
168    * collected), it returns an empty array.
169    */
getStackTrace()170   public StackTraceElement[] getStackTrace() {
171     int modulesCallStackSize = moduleSource.getStackTraceSize();
172     int chunkSize = partialCallStack.length;
173     int size = moduleSource.getStackTraceSize() + chunkSize;
174     StackTraceElement[] callStack = new StackTraceElement[size];
175     System.arraycopy(
176         StackTraceElements.convertToStackTraceElement(partialCallStack),
177         0,
178         callStack,
179         0,
180         chunkSize);
181     System.arraycopy(moduleSource.getStackTrace(), 0, callStack, chunkSize, modulesCallStackSize);
182     return callStack;
183   }
184 
185   /** Returns {@code getDeclaringSource().toString()} value. */
186   @Override
toString()187   public String toString() {
188     return getDeclaringSource().toString();
189   }
190 }
191