kopia lustrzana https://github.com/onthegomap/planetiler
52 wiersze
1.7 KiB
Java
52 wiersze
1.7 KiB
Java
package com.onthegomap.planetiler.util;
|
|
|
|
import java.io.IOException;
|
|
import java.io.UncheckedIOException;
|
|
import java.util.Objects;
|
|
import java.util.function.Predicate;
|
|
|
|
/**
|
|
* A class loader that loads certain classes even if they are already loaded by a parent classloader.
|
|
*
|
|
* This makes it possible to get multiple copies of the same class, so for example you could invoke a method
|
|
* synchronized on a static variable from different classes without contention.
|
|
*/
|
|
public class DuplicateClassLoader extends ClassLoader {
|
|
|
|
private final Predicate<String> shouldDuplicate;
|
|
|
|
private DuplicateClassLoader(Predicate<String> shouldDuplicate) {
|
|
this.shouldDuplicate = shouldDuplicate;
|
|
}
|
|
|
|
/**
|
|
* Returns a {@link ClassLoader} that loads every class with a name starting with {@code prefix} even if the parent
|
|
* has already loaded it.
|
|
*/
|
|
public static DuplicateClassLoader duplicateClassesWithPrefix(String prefix) {
|
|
return new DuplicateClassLoader(name -> name.startsWith(prefix));
|
|
}
|
|
|
|
@Override
|
|
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
|
if (shouldDuplicate.test(name)) {
|
|
Class<?> c = findLoadedClass(name);
|
|
if (c == null) {
|
|
byte[] b = loadClassFromFile(name);
|
|
return defineClass(name, b, 0, b.length);
|
|
}
|
|
}
|
|
return super.loadClass(name);
|
|
}
|
|
|
|
private byte[] loadClassFromFile(String fileName) {
|
|
String classFileName = fileName.replace('.', '/') + ".class";
|
|
try (var inputStream = getClass().getClassLoader().getResourceAsStream(classFileName)) {
|
|
return Objects.requireNonNull(inputStream, "Could not load " + fileName + " (" + classFileName + ")")
|
|
.readAllBytes();
|
|
} catch (IOException e) {
|
|
throw new UncheckedIOException(e);
|
|
}
|
|
}
|
|
}
|