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