Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find All Subclasses of a given class (Android)

I've used Reflections Library to Find All Subclasses of a given class in Java before.

This is a code snippet that I use in a simple java project :

    Reflections reflections = new Reflections(PACKAGE_NAME);

    Set<Class<? extends SuperClass>> subTypes =
            reflections.getSubTypesOf(SuperClass.class);

    for (Class<? extends SuperClass> subType : subTypes) {

        log("Subclass = " + subType.getSimpleName());
    }

When I run the same code in android project , "subType" List returns empty.

Can Anybody help me to get this work on Android ?

EDIT Jars I add for the whole thing to work are :

  • reflections-0.9.9-RC1-uberjar.jar
  • javassist-3.12.1.GA.jar
  • guava-14.0.1.jar
like image 346
Ivelius Avatar asked Oct 22 '22 02:10

Ivelius


2 Answers

maybe you can try this:

public abstract class ClassScanner {

    private static final String TAG = "ClassScanner"; 
    private Context mContext;

    public ClassScanner(Context context) {
        mContext = context;
    }

    public Context getContext() {
        return mContext;
    }

    void scan() throws IOException, ClassNotFoundException, NoSuchMethodException {
        long timeBegin = System.currentTimeMillis();

        PathClassLoader classLoader = (PathClassLoader) getContext().getClassLoader();
        //PathClassLoader classLoader = (PathClassLoader) Thread.currentThread().getContextClassLoader();//This also works good
        DexFile dexFile = new DexFile(getContext().getPackageCodePath());
        Enumeration<String> classNames = dexFile.entries();
        while (classNames.hasMoreElements()) {
            String className = classNames.nextElement();
            if (isTargetClassName(className)) {
                //Class<?> aClass = Class.forName(className);//java.lang.ExceptionInInitializerError
                //Class<?> aClass = Class.forName(className, false, classLoader);//tested on 魅蓝Note(M463C)_Android4.4.4 and Mi2s_Android5.1.1
                Class<?> aClass = classLoader.loadClass(className);//tested on 魅蓝Note(M463C)_Android4.4.4 and Mi2s_Android5.1.1
                if (isTargetClass(aClass)) {
                    onScanResult(aClass);
                }
            }
        }

        long timeEnd = System.currentTimeMillis();
        long timeElapsed = timeEnd - timeBegin;
        Log.d(TAG, "scan() cost " + timeElapsed + "ms");
    }

    protected abstract boolean isTargetClassName(String className);

    protected abstract boolean isTargetClass(Class clazz);

    protected abstract void onScanResult(Class clazz);
}

and this is a example how to use:

    new ClassScanner(context) {

    @Override
    protected boolean isTargetClassName(String className) {
        return className.startsWith(getContext().getPackageName())//I want classes under my package
                && !className.contains("$");//I don't need none-static inner classes
    }

    @Override
    protected boolean isTargetClass(Class clazz) {
        return AbsFactory.class.isAssignableFrom(clazz)//I want subclasses of AbsFactory
                && !Modifier.isAbstract(clazz.getModifiers());//I don't want abstract classes
    }

    @Override
    protected void onScanResult(Class clazz) {
        Constructor constructor = null;
        try {
            constructor = clazz.getDeclaredConstructor();
            constructor.setAccessible(true);
            constructor.newInstance();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

}.scan();
like image 94
fantouch Avatar answered Oct 23 '22 20:10

fantouch


This might not work due to the compilation process used in Android. The source code is converted into .class files with the Java compiler. The next step turns the .class files into Android .dex files (Dalvik bytecode) and they are unlikely to keep all meta-data.

http://developer.android.com/tools/building/index.html

like image 41
mach Avatar answered Oct 23 '22 19:10

mach