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