1package com.xtremelabs.robolectric.bytecode; 2 3import com.xtremelabs.robolectric.internal.Implements; 4 5import java.lang.reflect.Constructor; 6import java.lang.reflect.InvocationTargetException; 7import java.util.HashSet; 8import java.util.Set; 9 10@SuppressWarnings({"UnusedDeclaration"}) 11public class RobolectricInternals { 12 // initialized via magic by AndroidTranslator 13 private static ClassHandler classHandler; 14 private static Set<String> unloadableClassNames = new HashSet<String>(); 15 16 private static final ThreadLocal<Vars> ALL_VARS = new ThreadLocal<Vars>() { 17 @Override protected Vars initialValue() { 18 return new Vars(); 19 } 20 }; 21 22 private static class Vars { 23 Object callDirectly; 24 } 25 26 public static <T> T newInstanceOf(Class<T> clazz) { 27 try { 28 Constructor<T> defaultConstructor = clazz.getDeclaredConstructor(); 29 defaultConstructor.setAccessible(true); 30 return defaultConstructor.newInstance(); 31 } catch (InstantiationException e) { 32 throw new RuntimeException(e); 33 } catch (IllegalAccessException e) { 34 throw new RuntimeException(e); 35 } catch (NoSuchMethodException e) { 36 throw new RuntimeException(e); 37 } catch (InvocationTargetException e) { 38 throw new RuntimeException(e); 39 } 40 } 41 42 public static void bindShadowClass(Class<?> shadowClass) { 43 Implements realClass = shadowClass.getAnnotation(Implements.class); 44 if (realClass == null) { 45 throw new IllegalArgumentException(shadowClass + " is not annotated with @Implements"); 46 } 47 48 try { 49 ShadowWrangler.getInstance().bindShadowClass(realClass.value(), shadowClass); 50 } catch (TypeNotPresentException typeLoadingException) { 51 String unloadableClassName = shadowClass.getSimpleName(); 52 if (isIgnorableClassLoadingException(typeLoadingException)) { 53 //this allows users of the robolectric.jar file to use the non-Google APIs version of the api 54 if (unloadableClassNames.add(unloadableClassName)) { 55 System.out.println("Warning: an error occurred while binding shadow class: " + unloadableClassName); 56 } 57 } else { 58 throw typeLoadingException; 59 } 60 } 61 } 62 63 private static boolean isIgnorableClassLoadingException(Throwable typeLoadingException) { 64 if (typeLoadingException != null) { 65 // instanceof doesn't work here. Are we in different classloaders? 66 if (typeLoadingException.getClass().getName().equals(IgnorableClassNotFoundException.class.getName())) { 67 return true; 68 } 69 70 if (typeLoadingException instanceof NoClassDefFoundError 71 || typeLoadingException instanceof ClassNotFoundException 72 || typeLoadingException instanceof TypeNotPresentException) { 73 return isIgnorableClassLoadingException(typeLoadingException.getCause()); 74 } 75 } 76 return false; 77 } 78 79 public static <T> T directlyOn(T shadowedObject) { 80 Vars vars = ALL_VARS.get(); 81 82 if (vars.callDirectly != null) { 83 Object expectedInstance = vars.callDirectly; 84 vars.callDirectly = null; 85 throw new RuntimeException("already expecting a direct call on <" + expectedInstance + "> but here's a new request for <" + shadowedObject + ">"); 86 } 87 88 vars.callDirectly = shadowedObject; 89 return shadowedObject; 90 } 91 92 public static boolean shouldCallDirectly(Object directInstance) { 93 Vars vars = ALL_VARS.get(); 94 if (vars.callDirectly != null) { 95 if (vars.callDirectly != directInstance) { 96 Object expectedInstance = vars.callDirectly; 97 vars.callDirectly = null; 98 throw new RuntimeException("expected to perform direct call on <" + expectedInstance + "> but got <" + directInstance + ">"); 99 } else { 100 vars.callDirectly = null; 101 } 102 return true; 103 } else { 104 return false; 105 } 106 } 107 108 @SuppressWarnings({"UnusedDeclaration"}) 109 public static Object methodInvoked(Class clazz, String methodName, Object instance, String[] paramTypes, Object[] params) throws Throwable { 110 try { 111 return classHandler.methodInvoked(clazz, methodName, instance, paramTypes, params); 112 } catch(java.lang.LinkageError e) { 113 throw new Exception(e); 114 } 115 } 116 117 @SuppressWarnings({"UnusedDeclaration"}) 118 public static Object autobox(Object o) { 119 return o; 120 } 121 122 @SuppressWarnings({"UnusedDeclaration"}) 123 public static Object autobox(boolean o) { 124 return o; 125 } 126 127 @SuppressWarnings({"UnusedDeclaration"}) 128 public static Object autobox(byte o) { 129 return o; 130 } 131 132 @SuppressWarnings({"UnusedDeclaration"}) 133 public static Object autobox(char o) { 134 return o; 135 } 136 137 @SuppressWarnings({"UnusedDeclaration"}) 138 public static Object autobox(short o) { 139 return o; 140 } 141 142 @SuppressWarnings({"UnusedDeclaration"}) 143 public static Object autobox(int o) { 144 return o; 145 } 146 147 @SuppressWarnings({"UnusedDeclaration"}) 148 public static Object autobox(long o) { 149 return o; 150 } 151 152 @SuppressWarnings({"UnusedDeclaration"}) 153 public static Object autobox(float o) { 154 return o; 155 } 156 157 @SuppressWarnings({"UnusedDeclaration"}) 158 public static Object autobox(double o) { 159 return o; 160 } 161} 162