1 package org.robolectric.internal.bytecode; 2 3 import java.lang.reflect.InvocationTargetException; 4 import org.robolectric.internal.IShadow; 5 import org.robolectric.util.ReflectionHelpers; 6 7 public class ShadowImpl implements IShadow { 8 9 private final ProxyMaker proxyMaker = new ProxyMaker(this::directMethodName); 10 11 @Override 12 @SuppressWarnings("TypeParameterUnusedInFormals") extract(Object instance)13 public <T> T extract(Object instance) { 14 return (T) ((ShadowedObject) instance).$$robo$getData(); 15 } 16 newInstanceOf(Class<T> clazz)17 @Override public <T> T newInstanceOf(Class<T> clazz) { 18 return ReflectionHelpers.callConstructor(clazz); 19 } 20 21 @Override newInstance(Class<T> clazz, Class<?>[] parameterTypes, Object[] params)22 public <T> T newInstance(Class<T> clazz, Class<?>[] parameterTypes, Object[] params) { 23 return ReflectionHelpers.callConstructor(clazz, ReflectionHelpers.ClassParameter.fromComponentLists(parameterTypes, params)); 24 } 25 26 /** 27 * Returns a proxy object that invokes the original $$robo$$-prefixed methods for {@code 28 * shadowedObject}. 29 * 30 * @deprecated This is incompatible with JDK17+. Use a {@link 31 * org.robolectric.util.reflector.Reflector} interface with {@link 32 * org.robolectric.util.reflector.Direct}. 33 */ 34 @Deprecated 35 @Override directlyOn(T shadowedObject, Class<T> clazz)36 public <T> T directlyOn(T shadowedObject, Class<T> clazz) { 37 return createProxy(shadowedObject, clazz); 38 } 39 40 @Override 41 @SuppressWarnings(value = {"unchecked", "TypeParameterUnusedInFormals"}) directlyOn( Object shadowedObject, String clazzName, String methodName, ReflectionHelpers.ClassParameter<?>... paramValues)42 public <R> R directlyOn( 43 Object shadowedObject, 44 String clazzName, 45 String methodName, 46 ReflectionHelpers.ClassParameter<?>... paramValues) { 47 try { 48 Class<Object> aClass = 49 (Class<Object>) shadowedObject.getClass().getClassLoader().loadClass(clazzName); 50 return directlyOn(shadowedObject, aClass, methodName, paramValues); 51 } catch (ClassNotFoundException e) { 52 throw new RuntimeException(e); 53 } 54 } 55 56 @Override 57 @SuppressWarnings(value = {"unchecked", "TypeParameterUnusedInFormals"}) directlyOn( T shadowedObject, Class<T> clazz, String methodName, ReflectionHelpers.ClassParameter<?>... paramValues)58 public <R, T> R directlyOn( 59 T shadowedObject, 60 Class<T> clazz, 61 String methodName, 62 ReflectionHelpers.ClassParameter<?>... paramValues) { 63 String directMethodName = directMethodName(clazz.getName(), methodName); 64 return (R) 65 ReflectionHelpers.callInstanceMethod(clazz, shadowedObject, directMethodName, paramValues); 66 } 67 68 @Override 69 @SuppressWarnings(value = {"unchecked", "TypeParameterUnusedInFormals"}) directlyOn( Class<T> clazz, String methodName, ReflectionHelpers.ClassParameter<?>... paramValues)70 public <R, T> R directlyOn( 71 Class<T> clazz, String methodName, ReflectionHelpers.ClassParameter<?>... paramValues) { 72 String directMethodName = directMethodName(clazz.getName(), methodName); 73 return (R) ReflectionHelpers.callStaticMethod(clazz, directMethodName, paramValues); 74 } 75 createProxy(T shadowedObject, Class<T> clazz)76 private <T> T createProxy(T shadowedObject, Class<T> clazz) { 77 return proxyMaker.createProxy(clazz, shadowedObject); 78 } 79 80 @Override 81 @SuppressWarnings(value = {"unchecked", "TypeParameterUnusedInFormals"}) invokeConstructor( Class<? extends R> clazz, R instance, ReflectionHelpers.ClassParameter<?>... paramValues)82 public <R> R invokeConstructor( 83 Class<? extends R> clazz, R instance, ReflectionHelpers.ClassParameter<?>... paramValues) { 84 String directMethodName = 85 directMethodName(clazz.getName(), ShadowConstants.CONSTRUCTOR_METHOD_NAME); 86 return (R) ReflectionHelpers.callInstanceMethod(clazz, instance, directMethodName, paramValues); 87 } 88 89 @Override directMethodName(String className, String methodName)90 public String directMethodName(String className, String methodName) { 91 return ShadowConstants.ROBO_PREFIX 92 + className.replace('.', '_').replace('$', '_') 93 + "$" + methodName; 94 } 95 96 @Override directNativeMethodName(String className, String methodName)97 public String directNativeMethodName(String className, String methodName) { 98 return ShadowConstants.ROBO_PREFIX + methodName + "$nativeBinding"; 99 } 100 101 @Override directInitialize(Class<?> clazz)102 public void directInitialize(Class<?> clazz) { 103 try { 104 RobolectricInternals.performStaticInitialization(clazz); 105 } catch (InvocationTargetException | IllegalAccessException e) { 106 throw new RuntimeException("failed to initialize " + clazz, e); 107 } 108 } 109 110 } 111