• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.xtremelabs.robolectric.bytecode;
2 
3 import javassist.CannotCompileException;
4 import javassist.ClassPool;
5 import javassist.LoaderClassPath;
6 import javassist.NotFoundException;
7 
8 import java.io.File;
9 import java.lang.System;
10 import java.util.List;
11 
12 public class RobolectricClassLoader extends javassist.Loader {
13     private ClassCache classCache;
14     private AndroidTranslator androidTranslator;
15 
RobolectricClassLoader(ClassHandler classHandler)16     public RobolectricClassLoader(ClassHandler classHandler) {
17         this(classHandler, null);
18     }
19 
RobolectricClassLoader(ClassHandler classHandler, List<String> customClassNames)20     public RobolectricClassLoader(ClassHandler classHandler, List<String> customClassNames) {
21         super(RobolectricClassLoader.class.getClassLoader(), null);
22 
23         delegateLoadingOf(AndroidTranslator.class.getName());
24         delegateLoadingOf(ClassHandler.class.getName());
25 
26         final String classCachePath = System.getProperty("cached.robolectric.classes.path");
27         final File classCacheDirectory;
28         if (null == classCachePath || "".equals(classCachePath.trim())) {
29             classCacheDirectory = new File("./tmp");
30         } else {
31             classCacheDirectory = new File(classCachePath);
32         }
33 
34         classCache = new ClassCache(new File(classCacheDirectory, "cached-robolectric-classes.jar").getAbsolutePath(), AndroidTranslator.CACHE_VERSION);
35         try {
36             ClassPool classPool = new ClassPool();
37             classPool.appendClassPath(new LoaderClassPath(RobolectricClassLoader.class.getClassLoader()));
38 
39             androidTranslator = new AndroidTranslator(classHandler, classCache, customClassNames);
40             addTranslator(classPool, androidTranslator);
41         } catch (NotFoundException e) {
42             throw new RuntimeException(e);
43         } catch (CannotCompileException e) {
44             throw new RuntimeException(e);
45         }
46     }
47 
addCustomShadowClass(String classOrPackageToBeInstrumented)48     public void addCustomShadowClass(String classOrPackageToBeInstrumented) {
49         androidTranslator.addCustomShadowClass(classOrPackageToBeInstrumented);
50     }
51 
52     @Override
loadClass(String name)53     public Class loadClass(String name) throws ClassNotFoundException {
54         boolean shouldComeFromThisClassLoader = !(name.startsWith("org.junit") || name.startsWith("org.hamcrest")
55                 || name.startsWith("org.specs2") || name.startsWith("scala.")); //org.specs2 and scala. allows for android projects with mixed scala\java tests to be run with Maven Surefire (see the RoboSpecs project on github)
56 
57         Class<?> theClass;
58         if (shouldComeFromThisClassLoader) {
59             theClass = super.loadClass(name);
60         } else {
61             theClass = getParent().loadClass(name);
62         }
63 
64         return theClass;
65     }
66 
bootstrap(Class testClass)67     public Class<?> bootstrap(Class testClass) {
68         String testClassName = testClass.getName();
69 
70         try {
71             return loadClass(testClassName);
72         } catch (ClassNotFoundException e) {
73             throw new RuntimeException(e);
74         }
75     }
76 
77     @Override
findClass(String name)78     protected Class findClass(String name) throws ClassNotFoundException {
79         byte[] classBytes = classCache.getClassBytesFor(name);
80         if (classBytes != null) {
81             return defineClass(name, classBytes, 0, classBytes.length);
82         }
83         return super.findClass(name);
84     }
85 }
86