bytecodehackery/src/main/java/eu/mikroskeem/bytecodehackery/GeneratedClassLoader.java

64 lines
2.2 KiB
Java

package eu.mikroskeem.bytecodehackery;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class GeneratedClassLoader extends ClassLoader {
/*
* Note: "Stolen: from Techcable's Event4j,
* https://github.com/Techcable/Event4J/blob/master/src/main/java/net/techcable/event4j/asm/ASMEventExecutorFactory.java
*/
private static final ConcurrentMap<ClassLoader, GeneratedClassLoader> loaders = new ConcurrentHashMap<>();
public static GeneratedClassLoader getLoader(ClassLoader parent) {
return loaders.computeIfAbsent(Objects.requireNonNull(parent, "Null parent class-loader"), GeneratedClassLoader::new);
}
public Class<?> defineClass(String name, byte[] data) {
name = Objects.requireNonNull(name, "Null name").replace('/', '.');
synchronized (getClassLoadingLock(name)) {
if (hasClass(name)) throw new IllegalStateException(name + " already defined");
Class<?> c = this.define(name, Objects.requireNonNull(data, "Null data"));
if (!c.getName().equals(name)) throw new IllegalArgumentException("class name " + c.getName() + " != requested name " + name);
return c;
}
}
protected GeneratedClassLoader(ClassLoader parent) {
super(parent);
}
private Class<?> define(String name, byte[] data) {
synchronized (getClassLoadingLock(name)) {
if (hasClass(name)) throw new IllegalStateException("Already has class: " + name);
Class<?> c;
try {
c = defineClass(name, data, 0, data.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException("Illegal class data", e);
}
resolveClass(c);
return c;
}
}
@Override
public Object getClassLoadingLock(String name) {
return super.getClassLoadingLock(name);
}
public boolean hasClass(String name) {
synchronized (getClassLoadingLock(name)) {
try {
Class.forName(name);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
}