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

org.junit.extensions.cpsuite.ClasspathClassesFinder Maven / Gradle / Ivy

/*
 * @author Johannes Link ([email protected])
 * 
 * Published under Apache License, Version 2.0 (http://apache.org/licenses/LICENSE-2.0)
 */
package org.junit.extensions.cpsuite;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Utility class to find classes within the class path, both inside and outside
 * of jar files. Inner and anonymous classes are not being considered in the
 * first place.
 * 
 * It's originally evolved out of ClassPathTestCollector in JUnit 3.8.1
 */
public class ClasspathClassesFinder implements ClassesFinder {
	private Logger logger = LoggerFactory.getLogger(ClasspathClassesFinder.class);

	private static final int CLASS_SUFFIX_LENGTH = ".class".length();
	private static final String FALLBACK_CLASSPATH_PROPERTY = "java.class.path";

	private final ClassTester tester;

	private final String classpathProperty;

	public ClasspathClassesFinder(ClassTester tester, String classpathProperty) {
		this.tester = tester;
		this.classpathProperty = classpathProperty;
	}

	public List> find() {
		return findClassesInClasspath(getClasspath());
	}

	private String getClasspath() {
		String classPath = System.getProperty(getClasspathProperty());
		if (classPath == null)
			classPath = System.getProperty(FALLBACK_CLASSPATH_PROPERTY);
		return classPath;
	}

	private List> findClassesInClasspath(String classPath) {
		return findClassesInRoots(splitClassPath(classPath));
	}

	private List> findClassesInRoots(List roots) {
		List> classes = new ArrayList>(100);
		for (String root : roots) {
			gatherClassesInRoot(new File(root), classes);
		}
		return classes;
	}

	private void gatherClassesInRoot(File classRoot, List> classes) {
		Iterable relativeFilenames = new NullIterator();
		if (tester.searchInJars() && isJarFile(classRoot)) {
			try {
				relativeFilenames = new JarFilenameIterator(classRoot);
			} catch (IOException e) {
				// Don't iterate unavailable ja files
				e.printStackTrace();
			}
		} else if (classRoot.isDirectory()) {
			relativeFilenames = new RecursiveFilenameIterator(classRoot);
		}
		gatherClasses(classes, relativeFilenames);
	}

	private boolean isJarFile(File classRoot) {
		return classRoot.getName().endsWith(".jar") || classRoot.getName().endsWith(".JAR");
	}

	private void gatherClasses(List> classes, Iterable filenamesIterator) {
		for (String fileName : filenamesIterator) {
			if (!isClassFile(fileName)) {
				continue;
			}
			String className = classNameFromFile(fileName);
			if (!tester.acceptClassName(className)) {
				continue;
			}
			if (!tester.acceptInnerClass() && isInnerClass(className)) {
				continue;
			}
			try {
				Class clazz = Class.forName(className);
				if (clazz == null || clazz.isLocalClass() || clazz.isAnonymousClass()) {
					continue;
				}
				if (tester.acceptClass(clazz)) {
					classes.add(clazz);
				}
			} catch (Exception | Error ex) {
				// There might be a problem loading the class (like classpath problem,
				// ClassNotFoundException, NoClassDefFoundError etc)
				// We'll want to know about that to avoid classes to be accidentally
				// dropped out of suites
				logger.error("Couldn't load class " + className, ex);
			}
		}
	}

	private boolean isInnerClass(String className) {
		return className.contains("$");
	}

	private boolean isClassFile(String classFileName) {
		return classFileName.endsWith(".class");
	}

	private List splitClassPath(String classPath) {
		final String separator = System.getProperty("path.separator");
		return Arrays.asList(classPath.split(separator));
	}

	private String classNameFromFile(String classFileName) {
		// convert /a/b.class to a.b
		String s = replaceFileSeparators(cutOffExtension(classFileName));
		if (s.startsWith("."))
			return s.substring(1);
		return s;
	}

	private String replaceFileSeparators(String s) {
		String result = s.replace(File.separatorChar, '.');
		if (File.separatorChar != '/') {
			// In Jar-Files it's always '/'
			result = result.replace('/', '.');
		}
		return result;
	}

	private String cutOffExtension(String classFileName) {
		return classFileName.substring(0, classFileName.length() - CLASS_SUFFIX_LENGTH);
	}

	public ClassTester getTester() {
		return tester;
	}

	public String getClasspathProperty() {
		return classpathProperty;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy