1 package org.robolectric.internal.bytecode; 2 3 import java.lang.invoke.MethodHandle; 4 import java.lang.invoke.MethodType; 5 6 /** 7 * This interface is used by Robolectric when instrumented classes are created and interacted with. 8 */ 9 public interface ClassHandler { 10 11 /** 12 * Called by Robolectric when an instrumented class is first loaded into a sandbox and is ready 13 * to be statically initialized. 14 * 15 * This happens *in place of* any static initialization that may be performed by the class being 16 * loaded. The class will have a method named `__staticInitializer__` which may be invoked to 17 * perform its normal initialization from `<clinit>`. 18 * 19 * @param clazz the class being loaded 20 */ classInitializing(Class clazz)21 void classInitializing(Class clazz); 22 23 /** 24 * Called by Robolectric when a new instance of an instrumented class has been created and is 25 * ready to be initialized (but only on JVMs which don't support the `invokedynamic` instruction). 26 * 27 * This happens before constructor code executes on the new instance. 28 * 29 * Implementations may return an object which will be associated with the new instance and passed 30 * along on future calls to {@link #methodInvoked(String, boolean, Class)}. 31 * 32 * @param instance the newly-created instance 33 * @return a data value to be associated with the new instance 34 * @see #getShadowCreator(Class) for newer JVMs 35 */ initializing(Object instance)36 Object initializing(Object instance); 37 38 /** 39 * Called by Robolectric when an instrumented method is invoked. 40 * 41 * Implementations should return an {@link Plan}, which will be invoked with details about the 42 * current instance and parameters. 43 * 44 * Implementations may also return `null`, in which case the method's original code will be 45 * executed. 46 * 47 * @param signature the JVM internal-format signature of the method being invoked (e.g. 48 * `android/view/View/measure(II)V`) 49 * @param isStatic true if the method is static 50 * @param theClass the class on which the method is declared 51 * @return an execution plan, or `null` if the original method's code should be executed 52 * @see #findShadowMethodHandle(Class, String, MethodType, boolean) for newer JVMs 53 */ methodInvoked(String signature, boolean isStatic, Class<?> theClass)54 Plan methodInvoked(String signature, boolean isStatic, Class<?> theClass); 55 56 /** 57 * Called by Robolectric to determine how to create and initialize a shadow object when a new 58 * instance of an instrumented class has been instantiated. (but only on JVMs which support the 59 * `invokedynamic` instruction). 60 * 61 * The returned {@link MethodHandle} will be invoked after the new object has been allocated 62 * but before its constructor code is executed. 63 * 64 * Note that this is not directly analogous to {@link #initializing(Object)}; the return value 65 * from this method will be cached and used again for other instantiations of instances of the 66 * same class. 67 * 68 * @param theClass the instrumented class 69 * @return a data value to be associated with the new instance 70 * @see #getShadowCreator(Class) for older JVMs 71 * @see ShadowInvalidator for invalidating the returned {@link MethodHandle} 72 */ getShadowCreator(Class<?> theClass)73 MethodHandle getShadowCreator(Class<?> theClass); 74 75 /** 76 * Called by Robolectric when an instrumented method is invoked. 77 * 78 * Implementations should return an {@link MethodHandle}, which will be invoked with details about 79 * the current instance and parameters. 80 * 81 * Implementations may also return `null`, in which case the method's original code will be 82 * executed. 83 * 84 * @param theClass the class on which the method is declared 85 * @param name the name of the method 86 * @param methodType the method type 87 * @param isStatic true if the method is static 88 * @return a method handle to invoke, or `null` if the original method's code should be executed 89 * @see #methodInvoked(String, boolean, Class) for older JVMs 90 * @see ShadowInvalidator for invalidating the returned {@link MethodHandle} 91 */ findShadowMethodHandle(Class<?> theClass, String name, MethodType methodType, boolean isStatic)92 MethodHandle findShadowMethodHandle(Class<?> theClass, String name, MethodType methodType, 93 boolean isStatic) throws IllegalAccessException; 94 95 /** 96 * Called by Robolectric when an intercepted method is invoked. 97 * 98 * Unlike instrumented methods, calls to intercepted methods are modified in place by Robolectric 99 * in the calling code. This is useful when the method about to be invoked doesn't exist in the 100 * current JVM (e.g. because of Android differences). 101 * 102 * @param signature the JVM internal-format signature of the method being invoked (e.g. 103 * `android/view/View/measure(II)V`) 104 * @param instance the instance on which the method would have been invoked 105 * @param params the parameters to the method 106 * @param theClass the class on which the method is declared 107 * @return the value to be returned 108 * @throws Throwable if anything bad happens 109 */ intercept(String signature, Object instance, Object[] params, Class<?> theClass)110 Object intercept(String signature, Object instance, Object[] params, Class<?> theClass) 111 throws Throwable; 112 113 /** 114 * Removes Robolectric noise from stack traces. 115 * 116 * @param throwable the exception to be stripped 117 * @param <T> the type of exception 118 * @return the stripped stack trace 119 */ stripStackTrace(T throwable)120 <T extends Throwable> T stripStackTrace(T throwable); 121 122 /** 123 * An execution plan, which can be invoked to satisfy a requested method call. 124 */ 125 interface Plan { 126 run(Object instance, Object[] params)127 Object run(Object instance, Object[] params) throws Throwable; 128 describe()129 String describe(); 130 } 131 } 132