All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cucumber.runtime.android.DexClassFinder Maven / Gradle / Ivy

There is a newer version: 7.18.1
Show newest version
package cucumber.runtime.android;

import cucumber.runtime.ClassFinder;
import cucumber.runtime.CucumberException;
import dalvik.system.DexFile;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;

/**
 * Android specific implementation of {@link cucumber.runtime.ClassFinder} which loads classes contained in the provided {@link dalvik.system.DexFile}.
 */
final class DexClassFinder implements ClassFinder {

    /**
     * Symbol name of the manifest class.
     */
    private static final String MANIFEST_CLASS_NAME = "Manifest";

    /**
     * Symbol name of the resource class.
     */
    private static final String RESOURCE_CLASS_NAME = "R";

    /**
     * Symbol name prefix of any inner class of the resource class.
     */
    private static final String RESOURCE_INNER_CLASS_NAME_PREFIX = "R$";

    /**
     * The file name separator.
     */
    private static final String FILE_NAME_SEPARATOR = ".";

    /**
     * The class loader to actually load the classes specified by the {@link dalvik.system.DexFile}.
     */
    private static final ClassLoader CLASS_LOADER = DexClassFinder.class.getClassLoader();

    /**
     * The "symbol" representing the default package.
     */
    private static final String DEFAULT_PACKAGE = "";

    /**
     * The {@link dalvik.system.DexFile} to load classes from
     */
    private final DexFile dexFile;

    /**
     * Creates a new instance for the given parameter.
     *
     * @param dexFile the {@link dalvik.system.DexFile} to load classes from
     */
    DexClassFinder(final DexFile dexFile) {
        this.dexFile = dexFile;
    }

    @Override
    public  Collection> getDescendants(final Class parentType, final String packageName) {
        final List> result = new ArrayList>();

        final Enumeration entries = dexFile.entries();
        while (entries.hasMoreElements()) {
            final String className = entries.nextElement();
            if (isInPackage(className, packageName) && !isGenerated(className)) {
                try {
                    final Class clazz = loadClass(className);
                    if (clazz != null && !parentType.equals(clazz) && parentType.isAssignableFrom(clazz)) {
                        result.add(clazz.asSubclass(parentType));
                    }
                } catch (ClassNotFoundException e) {
                    throw new CucumberException(e);
                }
            }
        }
        return result;
    }

    @Override
    public  Class loadClass(final String className) throws ClassNotFoundException {
        return (Class) Class.forName(className, false, CLASS_LOADER);
    }

    private boolean isInPackage(final String className, final String packageName) {
        final int lastDotIndex = className.lastIndexOf(FILE_NAME_SEPARATOR);
        final String classPackage = lastDotIndex == -1 ? DEFAULT_PACKAGE : className.substring(0, lastDotIndex);
        return classPackage.startsWith(packageName);
    }

    private boolean isGenerated(final String className) {
        final int lastDotIndex = className.lastIndexOf(FILE_NAME_SEPARATOR);
        final String shortName = lastDotIndex == -1 ? className : className.substring(lastDotIndex + 1);
        return shortName.equals(MANIFEST_CLASS_NAME) || shortName.equals(RESOURCE_CLASS_NAME) || shortName.startsWith(RESOURCE_INNER_CLASS_NAME_PREFIX);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy