org.junit.gen5.commons.util.ClasspathScanner Maven / Gradle / Ivy
Show all versions of junit-commons Show documentation
/*
* Copyright 2015-2016 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.junit.gen5.commons.util;
import static org.junit.gen5.commons.meta.API.Usage.Internal;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.junit.gen5.commons.meta.API;
/**
* DISCLAIMER
*
* These utilities are intended solely for usage within the JUnit framework
* itself. Any usage by external parties is not supported.
* Use at your own risk!
*
* @since 5.0
*/
@API(Internal)
class ClasspathScanner {
private static final String CLASS_FILE_SUFFIX = ".class";
private final Supplier classLoaderSupplier;
private final BiFunction>> loadClass;
ClasspathScanner(Supplier classLoaderSupplier,
BiFunction>> loadClass) {
this.classLoaderSupplier = classLoaderSupplier;
this.loadClass = loadClass;
}
boolean isPackage(String packageName) {
String path = packagePath(packageName);
try {
Enumeration resource = classLoaderSupplier.get().getResources(path);
return resource.hasMoreElements();
}
catch (IOException e) {
return false;
}
}
List> scanForClassesInPackage(String basePackageName, Predicate> classFilter) {
Preconditions.notBlank(basePackageName, "basePackageName must not be blank");
List dirs = allSourceDirsForPackage(basePackageName);
return allClassesInSourceDirs(dirs, basePackageName, classFilter);
}
private List> allClassesInSourceDirs(List sourceDirs, String basePackageName,
Predicate> classFilter) {
List> classes = new ArrayList<>();
for (File aSourceDir : sourceDirs) {
classes.addAll(findClassesInSourceDirRecursively(aSourceDir, basePackageName, classFilter));
}
return classes;
}
List> scanForClassesInClasspathRoot(File root, Predicate> classFilter) {
Preconditions.notNull(root, () -> "root must not be null");
Preconditions.condition(root.exists(),
() -> "root must exist, but could not be found: " + root.getAbsolutePath());
Preconditions.condition(root.isDirectory(), "root must be a directory, but is not: " + root.getAbsolutePath());
return findClassesInSourceDirRecursively(root, "", classFilter);
}
private List allSourceDirsForPackage(String basePackageName) {
try {
ClassLoader classLoader = classLoaderSupplier.get();
String path = packagePath(basePackageName);
Enumeration resources = classLoader.getResources(path);
List dirs = new ArrayList<>();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
dirs.add(new File(resource.getFile()));
}
return dirs;
}
catch (IOException e) {
return Collections.emptyList();
}
}
private String packagePath(String basePackageName) {
return basePackageName.replace('.', '/');
}
private List> findClassesInSourceDirRecursively(File sourceDir, String packageName,
Predicate> classFilter) {
List> classesCollector = new ArrayList<>();
collectClassesRecursively(sourceDir, packageName, classesCollector, classFilter);
return classesCollector;
}
private void collectClassesRecursively(File sourceDir, String packageName, List> classesCollector,
Predicate> classFilter) {
File[] files = sourceDir.listFiles();
if (files == null) {
return;
}
for (File file : files) {
if (isClassFile(file)) {
Optional> classForClassFile = loadClassForClassFile(file, packageName);
classForClassFile.filter(classFilter).ifPresent(clazz -> classesCollector.add(clazz));
}
else if (file.isDirectory()) {
collectClassesRecursively(file, appendPackageName(packageName, file.getName()), classesCollector,
classFilter);
}
}
}
private String appendPackageName(String packageName, String subpackageName) {
if (packageName.isEmpty())
return subpackageName;
else
return packageName + "." + subpackageName;
}
private Optional> loadClassForClassFile(File file, String packageName) {
String className = packageName + '.'
+ file.getName().substring(0, file.getName().length() - CLASS_FILE_SUFFIX.length());
return loadClass.apply(className, classLoaderSupplier.get());
}
private static boolean isClassFile(File file) {
return file.isFile() && file.getName().endsWith(CLASS_FILE_SUFFIX);
}
}