FileDocCategorySizeDatePackage
DependencyFinder.javaAPI DocAndroid 5.1 API26216Thu Mar 12 22:22:44 GMT 2015com.android.tools.layoutlib.create

DependencyFinder

public class DependencyFinder extends Object
Analyzes the input JAR using the ASM java bytecode manipulation library to list the classes and their dependencies. A "dependency" is a class used by another class.

Fields Summary
private final Log
mLog
Output logger.
Constructors Summary
public DependencyFinder(Log log)
Creates a new analyzer.

param
log The log output.

        mLog = log;
    
Methods Summary
static java.lang.StringclassReaderToClassName(org.objectweb.asm.ClassReader classReader)
Utility that returns the fully qualified binary class name for a ClassReader. E.g. it returns something like android.view.View.

        if (classReader == null) {
            return null;
        } else {
            return classReader.getClassName().replace('/", '.");
        }
    
java.util.MapfindClassesDeps(java.util.Map zipClasses)
Finds all dependencies for all classes in keepClasses which are also listed in zipClasses. Returns a map of all the dependencies found.


        // The dependencies that we'll collect.
        // It's a map Class name => uses class names.
        Map<String, Set<String>> dependencyMap = new TreeMap<String, Set<String>>();

        DependencyVisitor visitor = getVisitor();

        int count = 0;
        try {
            for (Entry<String, ClassReader> entry : zipClasses.entrySet()) {
                String name = entry.getKey();

                TreeSet<String> set = new TreeSet<String>();
                dependencyMap.put(name, set);
                visitor.setDependencySet(set);

                ClassReader cr = entry.getValue();
                cr.accept(visitor, 0 /* flags */);

                visitor.setDependencySet(null);

                mLog.debugNoln("Visited %d classes\r", ++count);
            }
        } finally {
            mLog.debugNoln("\n");
        }

        return dependencyMap;
    
public java.util.ListfindDeps(java.util.List osJarPath)
Starts the analysis using parameters from the constructor.

param
osJarPath The input source JARs to parse.
return
A pair: [0]: map { class FQCN => set of FQCN class dependencies }. [1]: map { missing class FQCN => set of FQCN class that uses it. }


        Map<String, ClassReader> zipClasses = parseZip(osJarPath);
        mLog.info("Found %d classes in input JAR%s.",
                zipClasses.size(),
                osJarPath.size() > 1 ? "s" : "");

        Map<String, Set<String>> deps = findClassesDeps(zipClasses);

        Map<String, Set<String>> missing = findMissingClasses(deps, zipClasses.keySet());

        List<Map<String, Set<String>>> result = new ArrayList<Map<String,Set<String>>>(2);
        result.add(deps);
        result.add(missing);
        return result;
    
private java.util.MapfindMissingClasses(java.util.Map deps, java.util.Set zipClasses)
Computes which classes FQCN were found as dependencies that are NOT listed in the original JAR classes.

param
deps The map { FQCN => dependencies[] } returned by {@link #findClassesDeps(Map)}.
param
zipClasses The set of all classes FQCN found in the JAR files.
return
A map { FQCN not found in the zipClasses => classes using it }

        Map<String, Set<String>> missing = new TreeMap<String, Set<String>>();

        for (Entry<String, Set<String>> entry : deps.entrySet()) {
            String name = entry.getKey();

            for (String dep : entry.getValue()) {
                if (!zipClasses.contains(dep)) {
                    // This dependency doesn't exist in the zip classes.
                    Set<String> set = missing.get(dep);
                    if (set == null) {
                        set = new TreeSet<String>();
                        missing.put(dep, set);
                    }
                    set.add(name);
                }
            }

        }

        return missing;
    
com.android.tools.layoutlib.create.DependencyFinder$DependencyVisitorgetVisitor()
Instantiates a new DependencyVisitor. Useful for unit tests.

        return new DependencyVisitor();
    
static java.lang.StringinternalToBinaryClassName(java.lang.String className)
Utility that returns the fully qualified binary class name from a path-like FQCN. E.g. it returns android.view.View from android/view/View.

        if (className == null) {
            return null;
        } else {
            return className.replace('/", '.");
        }
    
java.util.MapparseZip(java.util.List jarPathList)
Parses a JAR file and returns a list of all classes founds using a map class name => ASM ClassReader. Class names are in the form "android.view.View".

        TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>();

        for (String jarPath : jarPathList) {
            ZipFile zip = new ZipFile(jarPath);
            Enumeration<? extends ZipEntry> entries = zip.entries();
            ZipEntry entry;
            while (entries.hasMoreElements()) {
                entry = entries.nextElement();
                if (entry.getName().endsWith(".class")) {
                    ClassReader cr = new ClassReader(zip.getInputStream(entry));
                    String className = classReaderToClassName(cr);
                    classes.put(className, cr);
                }
            }
        }

        return classes;
    
public voidprintAllDeps(java.util.List result)
Prints dependencies to the current logger, found stuff and missing stuff.

        assert result.size() == 2;
        Map<String, Set<String>> deps = result.get(0);
        Map<String, Set<String>> missing = result.get(1);

        // Print all dependences found in the format:
        // +Found: <FQCN from zip>
        //     uses: FQCN

        mLog.info("++++++ %d Entries found in source JARs", deps.size());
        mLog.info("");

        for (Entry<String, Set<String>> entry : deps.entrySet()) {
            mLog.info(    "+Found  : %s", entry.getKey());
            for (String dep : entry.getValue()) {
                mLog.info("    uses: %s", dep);
            }

            mLog.info("");
        }


        // Now print all missing dependences in the format:
        // -Missing <FQCN>:
        //     used by: <FQCN>

        mLog.info("");
        mLog.info("------ %d Entries missing from source JARs", missing.size());
        mLog.info("");

        for (Entry<String, Set<String>> entry : missing.entrySet()) {
            mLog.info(    "-Missing  : %s", entry.getKey());
            for (String dep : entry.getValue()) {
                mLog.info("   used by: %s", dep);
            }

            mLog.info("");
        }
    
public voidprintMissingDeps(java.util.List result)
Prints only a summary of the missing dependencies to the current logger.

        assert result.size() == 2;
        @SuppressWarnings("unused") Map<String, Set<String>> deps = result.get(0);
        Map<String, Set<String>> missing = result.get(1);

        for (String fqcn : missing.keySet()) {
            mLog.info("%s", fqcn);
        }