added PathClassLoaderTest

This commit is contained in:
2021-07-01 22:21:26 +01:00
parent 299367fb74
commit 8ea2268491
4 changed files with 106 additions and 40 deletions

View File

@@ -26,8 +26,14 @@ allprojects {
}
}
configurations {
pathClassloaderTest
}
dependencies {
implementation group: "org.slf4j", name: "slf4j-api", version: getProperty('slf4j.version')
pathClassloaderTest group: 'com.google.inject', name: 'guice', version: getProperty('guice.version')
}
compileJava {
@@ -41,8 +47,13 @@ jar {
])
}
}
TaskProvider<Zip> pathClassLoaderTestBundleTask = tasks.register("pathClassLoaderTestBundle", Zip) {
from(configurations.pathClassloaderTest)
archiveBaseName = "pathClassLoaderTestBundle"
}
test {
inputs.files(pathClassLoaderTestBundleTask)
useJUnitPlatform()
Dependency junitJupiterEngineDependency =
dependencies.create(
@@ -59,7 +70,8 @@ test {
ResolvedArtifact resolvedArtifact -> resolvedArtifact.file
}.first()
systemProperties([
'junit.jupiter.engine.jar' : junitJupiterEngineJar.toString()
'junit.jupiter.engine.jar' : junitJupiterEngineJar.toString(),
'path.classloader.test.bundle' : pathClassLoaderTestBundleTask.get().outputs.files.singleFile
])
}
@@ -82,3 +94,4 @@ publishing {
}

View File

@@ -3,3 +3,4 @@ jwo.version=1.0
junitJupiter.version=5.7.0
lombok.version=1.18.16
slf4j.version=1.7.30
guice.version = 5.0.1

View File

@@ -9,81 +9,85 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.*;
/**
* A classloader that loads classes from a {@link Path} instance
*/
public final class PathClassLoader extends ClassLoader {
private final Path path;
private final Iterable<Path> paths;
static {
registerAsParallelCapable();
}
public PathClassLoader(Path path) {
this(path, null);
public PathClassLoader(Path ...path) {
this(Arrays.asList(path), null);
}
public PathClassLoader(Path path, ClassLoader parent) {
public PathClassLoader(Iterable<Path> paths) {
this(paths, null);
}
public PathClassLoader(Iterable<Path> paths, ClassLoader parent) {
super(parent);
this.path = path;
this.paths = paths;
}
@Override
@SneakyThrows
protected Class<?> findClass(String name) {
Path classPath = path.resolve(name.replace('.', '/').concat(".class"));
if (Files.exists(classPath)) {
byte[] byteCode = Files.readAllBytes(classPath);
return defineClass(name, byteCode, 0, byteCode.length);
} else {
throw new ClassNotFoundException(name);
for(Path path : paths) {
Path classPath = path.resolve(name.replace('.', '/').concat(".class"));
if (Files.exists(classPath)) {
byte[] byteCode = Files.readAllBytes(classPath);
return defineClass(name, byteCode, 0, byteCode.length);
}
}
throw new ClassNotFoundException(name);
}
@Override
@SneakyThrows
protected URL findResource(String name) {
Path resolved = path.resolve(name);
if (Files.exists(resolved)) {
return toURL(resolved);
} else {
return null;
for(Path path : paths) {
Path resolved = path.resolve(name);
if (Files.exists(resolved)) {
return toURL(resolved);
}
}
return null;
}
@Override
protected Enumeration<URL> findResources(final String name) throws IOException {
final List<URL> resources = new ArrayList<>(1);
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (!name.isEmpty()) {
this.addIfMatches(resources, file);
for(Path path : paths) {
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (!name.isEmpty()) {
this.addIfMatches(resources, file);
}
return super.visitFile(file, attrs);
}
return super.visitFile(file, attrs);
}
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
if (!name.isEmpty() || path.equals(dir)) {
this.addIfMatches(resources, dir);
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
if (!name.isEmpty() || path.equals(dir)) {
this.addIfMatches(resources, dir);
}
return super.preVisitDirectory(dir, attrs);
}
return super.preVisitDirectory(dir, attrs);
}
void addIfMatches(List<URL> resources, Path file) throws IOException {
if (path.relativize(file).toString().equals(name)) {
resources.add(toURL(file));
void addIfMatches(List<URL> resources, Path file) throws IOException {
if (path.relativize(file).toString().equals(name)) {
resources.add(toURL(file));
}
}
}
});
});
}
return Collections.enumeration(resources);
}

View File

@@ -0,0 +1,48 @@
package net.woggioni.jwo.loader;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class PathClassLoaderTest {
Path testBundle = Path.of(System.getProperty("path.classloader.test.bundle"));
@Test
@SneakyThrows
void test() {
FileSystem fs = FileSystems.newFileSystem(testBundle, null);
List<Path> paths = StreamSupport.stream(fs.getRootDirectories().spliterator(), false).flatMap(new Function<Path, Stream<Path>>() {
@Override
@SneakyThrows
public Stream<Path> apply(Path path) {
return Files.list(path)
.filter(Files::isRegularFile)
.filter(p -> p.getFileName().toString().endsWith(".jar"));
}
}).flatMap(new Function<Path, Stream<Path>>() {
@Override
@SneakyThrows
public Stream<Path> apply(Path path) {
System.out.println(path.getFileName().toString());
return StreamSupport.stream(FileSystems.newFileSystem(path, null).getRootDirectories().spliterator(), false);
}
}).collect(Collectors.toUnmodifiableList());
PathClassLoader classLoader = new PathClassLoader(paths);
Class<?>[] cls = new Class[1];
Assertions.assertDoesNotThrow(() -> {
cls[0] = classLoader.loadClass("com.google.common.collect.ImmutableMap");
});
Assertions.assertNotNull(cls[0]);
}
}