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