Home | History | Annotate | Download | only in spi
      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    */
     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    */
    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    */
    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    */
    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    */
    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    */
    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
    189   public String toString() {
    190     return getDeclaringSource().toString();
    191   }
    192 }
    193