1b5d56e95f27d484ad3098ac18867262e7c8826c1Christian Williams & Phil Goodwinpackage com.xtremelabs.robolectric.bytecode;
26eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
36eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulzimport javassist.CannotCompileException;
46eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulzimport javassist.ClassPool;
56eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulzimport javassist.LoaderClassPath;
66eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulzimport javassist.NotFoundException;
76eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
85b84e76cc69c352ca8116992b2646d0d0cb83370kopsimport java.io.File;
95b84e76cc69c352ca8116992b2646d0d0cb83370kopsimport java.lang.System;
10f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richardimport java.util.List;
11f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard
12f04aa508b5ca76c53da614ced913d7be4632f09bChristian Williams & Phil Goodwinpublic class RobolectricClassLoader extends javassist.Loader {
1330291fcbfe19f4959102bacdc65dddb9a3715b74Christian Williams & Phil Goodwin    private ClassCache classCache;
14f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard    private AndroidTranslator androidTranslator;
15e7c2aaf28ca0949241e45085ae056c014c3bbe59Tyler Schultz
16f04aa508b5ca76c53da614ced913d7be4632f09bChristian Williams & Phil Goodwin    public RobolectricClassLoader(ClassHandler classHandler) {
17752e0b034b3fca97eb39bac82f91b5ad7788be10Tyler Schultz        this(classHandler, null);
18b9116a1018de7bd622d18742d589eca4b5a12983Kathy Lin    }
19752e0b034b3fca97eb39bac82f91b5ad7788be10Tyler Schultz
20f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard    public RobolectricClassLoader(ClassHandler classHandler, List<String> customClassNames) {
21f04aa508b5ca76c53da614ced913d7be4632f09bChristian Williams & Phil Goodwin        super(RobolectricClassLoader.class.getClassLoader(), null);
226eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
236eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        delegateLoadingOf(AndroidTranslator.class.getName());
24e876a8fad71b3098795fc08a08f794795123442bChristian Williams        delegateLoadingOf(ClassHandler.class.getName());
256eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
26752e0b034b3fca97eb39bac82f91b5ad7788be10Tyler Schultz        final String classCachePath = System.getProperty("cached.robolectric.classes.path");
275b84e76cc69c352ca8116992b2646d0d0cb83370kops        final File classCacheDirectory;
285b84e76cc69c352ca8116992b2646d0d0cb83370kops        if (null == classCachePath || "".equals(classCachePath.trim())) {
295b84e76cc69c352ca8116992b2646d0d0cb83370kops            classCacheDirectory = new File("./tmp");
305b84e76cc69c352ca8116992b2646d0d0cb83370kops        } else {
315b84e76cc69c352ca8116992b2646d0d0cb83370kops            classCacheDirectory = new File(classCachePath);
325b84e76cc69c352ca8116992b2646d0d0cb83370kops        }
335b84e76cc69c352ca8116992b2646d0d0cb83370kops
345b84e76cc69c352ca8116992b2646d0d0cb83370kops        classCache = new ClassCache(new File(classCacheDirectory, "cached-robolectric-classes.jar").getAbsolutePath(), AndroidTranslator.CACHE_VERSION);
356eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        try {
366eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz            ClassPool classPool = new ClassPool();
37f04aa508b5ca76c53da614ced913d7be4632f09bChristian Williams & Phil Goodwin            classPool.appendClassPath(new LoaderClassPath(RobolectricClassLoader.class.getClassLoader()));
386eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
39f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard            androidTranslator = new AndroidTranslator(classHandler, classCache, customClassNames);
40e7c2aaf28ca0949241e45085ae056c014c3bbe59Tyler Schultz            addTranslator(classPool, androidTranslator);
416eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        } catch (NotFoundException e) {
426eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz            throw new RuntimeException(e);
436eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        } catch (CannotCompileException e) {
446eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz            throw new RuntimeException(e);
456eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        }
46f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard    }
47f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard
48f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard    public void addCustomShadowClass(String classOrPackageToBeInstrumented) {
49f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard        androidTranslator.addCustomShadowClass(classOrPackageToBeInstrumented);
50f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard    }
51f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard
526eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    @Override
536eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    public Class loadClass(String name) throws ClassNotFoundException {
54752e0b034b3fca97eb39bac82f91b5ad7788be10Tyler Schultz        boolean shouldComeFromThisClassLoader = !(name.startsWith("org.junit") || name.startsWith("org.hamcrest")
55752e0b034b3fca97eb39bac82f91b5ad7788be10Tyler Schultz                || 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)
56e7c2aaf28ca0949241e45085ae056c014c3bbe59Tyler Schultz
576eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        Class<?> theClass;
586eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        if (shouldComeFromThisClassLoader) {
596eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz            theClass = super.loadClass(name);
606eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        } else {
616eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz            theClass = getParent().loadClass(name);
626eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        }
636eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
646eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        return theClass;
656eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    }
666eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
676eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    public Class<?> bootstrap(Class testClass) {
686eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        String testClassName = testClass.getName();
696eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
706eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        try {
716eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz            return loadClass(testClassName);
726eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        } catch (ClassNotFoundException e) {
736eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz            throw new RuntimeException(e);
746eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        }
756eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    }
76e7c2aaf28ca0949241e45085ae056c014c3bbe59Tyler Schultz
77752e0b034b3fca97eb39bac82f91b5ad7788be10Tyler Schultz    @Override
78752e0b034b3fca97eb39bac82f91b5ad7788be10Tyler Schultz    protected Class findClass(String name) throws ClassNotFoundException {
7930291fcbfe19f4959102bacdc65dddb9a3715b74Christian Williams & Phil Goodwin        byte[] classBytes = classCache.getClassBytesFor(name);
8030291fcbfe19f4959102bacdc65dddb9a3715b74Christian Williams & Phil Goodwin        if (classBytes != null) {
8130291fcbfe19f4959102bacdc65dddb9a3715b74Christian Williams & Phil Goodwin            return defineClass(name, classBytes, 0, classBytes.length);
82e7c2aaf28ca0949241e45085ae056c014c3bbe59Tyler Schultz        }
83e7c2aaf28ca0949241e45085ae056c014c3bbe59Tyler Schultz        return super.findClass(name);
84e7c2aaf28ca0949241e45085ae056c014c3bbe59Tyler Schultz    }
856eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz}
86