Skip to content

Commit

Permalink
Added package definer that is responsible for defining packages when …
Browse files Browse the repository at this point in the history
…loading classes. Without an explicit package definition, package representations do not exist at runtime.
  • Loading branch information
Rafael Winterhalter committed Aug 6, 2015
1 parent fab52ec commit 92be204
Show file tree
Hide file tree
Showing 10 changed files with 1,093 additions and 327 deletions.
Expand Up @@ -33,6 +33,11 @@ public class ByteArrayClassLoader extends ClassLoader {
*/ */
protected final ProtectionDomain protectionDomain; protected final ProtectionDomain protectionDomain;


/**
* The package definer to be queried for package definitions.
*/
protected final PackageDefiner packageDefiner;

/** /**
* The access control context of this class loader's instantiation. * The access control context of this class loader's instantiation.
*/ */
Expand All @@ -45,16 +50,19 @@ public class ByteArrayClassLoader extends ClassLoader {
* @param typeDefinitions A map of fully qualified class names pointing to their binary representations. * @param typeDefinitions A map of fully qualified class names pointing to their binary representations.
* @param protectionDomain The protection domain to apply where {@code null} references an implicit * @param protectionDomain The protection domain to apply where {@code null} references an implicit
* protection domain. * protection domain.
* @param packageDefiner The package definer to be queried for package definitions.
* @param persistenceHandler The persistence handler of this class loader. * @param persistenceHandler The persistence handler of this class loader.
*/ */
public ByteArrayClassLoader(ClassLoader parent, public ByteArrayClassLoader(ClassLoader parent,
Map<String, byte[]> typeDefinitions, Map<String, byte[]> typeDefinitions,
ProtectionDomain protectionDomain, ProtectionDomain protectionDomain,
PersistenceHandler persistenceHandler) { PersistenceHandler persistenceHandler,
PackageDefiner packageDefiner) {
super(parent); super(parent);
this.typeDefinitions = new HashMap<String, byte[]>(typeDefinitions); this.typeDefinitions = new HashMap<String, byte[]>(typeDefinitions);
this.protectionDomain = protectionDomain; this.protectionDomain = protectionDomain;
this.persistenceHandler = persistenceHandler; this.persistenceHandler = persistenceHandler;
this.packageDefiner = packageDefiner;
accessControlContext = AccessController.getContext(); accessControlContext = AccessController.getContext();
} }


Expand All @@ -66,6 +74,7 @@ public ByteArrayClassLoader(ClassLoader parent,
* @param protectionDomain The protection domain to apply where {@code null} references an implicit * @param protectionDomain The protection domain to apply where {@code null} references an implicit
* protection domain. * protection domain.
* @param persistenceHandler The persistence handler to be used by the created class loader. * @param persistenceHandler The persistence handler to be used by the created class loader.
* @param packageDefiner The package definer to be queried for package definitions.
* @param childFirst {@code true} if the class loader should apply child first semantics when loading * @param childFirst {@code true} if the class loader should apply child first semantics when loading
* the {@code typeDefinitions}. * the {@code typeDefinitions}.
* @return A corresponding class loader. * @return A corresponding class loader.
Expand All @@ -74,14 +83,15 @@ public static ClassLoader of(ClassLoader parent,
Map<TypeDescription, byte[]> typeDefinitions, Map<TypeDescription, byte[]> typeDefinitions,
ProtectionDomain protectionDomain, ProtectionDomain protectionDomain,
PersistenceHandler persistenceHandler, PersistenceHandler persistenceHandler,
PackageDefiner packageDefiner,
boolean childFirst) { boolean childFirst) {
Map<String, byte[]> rawTypeDefinitions = new HashMap<String, byte[]>(typeDefinitions.size()); Map<String, byte[]> rawTypeDefinitions = new HashMap<String, byte[]>(typeDefinitions.size());
for (Map.Entry<TypeDescription, byte[]> entry : typeDefinitions.entrySet()) { for (Map.Entry<TypeDescription, byte[]> entry : typeDefinitions.entrySet()) {
rawTypeDefinitions.put(entry.getKey().getName(), entry.getValue()); rawTypeDefinitions.put(entry.getKey().getName(), entry.getValue());
} }
return childFirst return childFirst
? new ChildFirst(parent, rawTypeDefinitions, protectionDomain, persistenceHandler) ? new ChildFirst(parent, rawTypeDefinitions, protectionDomain, persistenceHandler, packageDefiner)
: new ByteArrayClassLoader(parent, rawTypeDefinitions, protectionDomain, persistenceHandler); : new ByteArrayClassLoader(parent, rawTypeDefinitions, protectionDomain, persistenceHandler, packageDefiner);
} }


/** /**
Expand All @@ -92,6 +102,7 @@ public static ClassLoader of(ClassLoader parent,
* @param protectionDomain The protection domain to apply where {@code null} references an implicit * @param protectionDomain The protection domain to apply where {@code null} references an implicit
* protection domain. * protection domain.
* @param persistenceHandler The persistence handler of the created class loader. * @param persistenceHandler The persistence handler of the created class loader.
* @param packageDefiner The package definer to be queried for package definitions.
* @param childFirst {@code true} {@code true} if the created class loader should apply child-first * @param childFirst {@code true} {@code true} if the created class loader should apply child-first
* semantics when loading the {@code types}. * semantics when loading the {@code types}.
* @return A map of the given type descriptions pointing to their loaded representations. * @return A map of the given type descriptions pointing to their loaded representations.
Expand All @@ -100,14 +111,15 @@ public static Map<TypeDescription, Class<?>> load(ClassLoader classLoader,
Map<TypeDescription, byte[]> types, Map<TypeDescription, byte[]> types,
ProtectionDomain protectionDomain, ProtectionDomain protectionDomain,
PersistenceHandler persistenceHandler, PersistenceHandler persistenceHandler,
PackageDefiner packageDefiner,
boolean childFirst) { boolean childFirst) {
Map<TypeDescription, Class<?>> loadedTypes = new LinkedHashMap<TypeDescription, Class<?>>(types.size()); Map<TypeDescription, Class<?>> loadedTypes = new LinkedHashMap<TypeDescription, Class<?>>(types.size());
classLoader = ByteArrayClassLoader.of(classLoader, types, protectionDomain, persistenceHandler, childFirst); classLoader = ByteArrayClassLoader.of(classLoader, types, protectionDomain, persistenceHandler, packageDefiner, childFirst);
for (TypeDescription typeDescription : types.keySet()) { for (TypeDescription typeDescription : types.keySet()) {
try { try {
loadedTypes.put(typeDescription, classLoader.loadClass(typeDescription.getName())); loadedTypes.put(typeDescription, classLoader.loadClass(typeDescription.getName()));
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException exception) {
throw new IllegalStateException("Cannot load class " + typeDescription, e); throw new IllegalStateException("Cannot load class " + typeDescription, exception);
} }
} }
return loadedTypes; return loadedTypes;
Expand All @@ -116,11 +128,14 @@ public static Map<TypeDescription, Class<?>> load(ClassLoader classLoader,
@Override @Override
protected Class<?> findClass(String name) throws ClassNotFoundException { protected Class<?> findClass(String name) throws ClassNotFoundException {
try { try {
// This does not need synchronization because this method is only called from within
// ClassLoader in a synchronized context.
return AccessController.doPrivileged(new ClassLoadingAction(name), accessControlContext); return AccessController.doPrivileged(new ClassLoadingAction(name), accessControlContext);
} catch (PrivilegedActionException e) { } catch (PrivilegedActionException exception) {
throw (ClassNotFoundException) e.getCause(); Throwable cause = exception.getCause();
if (cause instanceof ClassNotFoundException) {
throw (ClassNotFoundException) cause;
} else {
throw new IllegalStateException("Could not load class " + name, cause);
}
} }
} }


Expand All @@ -141,6 +156,7 @@ public String toString() {
", typeDefinitions=" + typeDefinitions + ", typeDefinitions=" + typeDefinitions +
", persistenceHandler=" + persistenceHandler + ", persistenceHandler=" + persistenceHandler +
", protectionDomain=" + protectionDomain + ", protectionDomain=" + protectionDomain +
", packageDefiner=" + packageDefiner +
", accessControlContext=" + accessControlContext + ", accessControlContext=" + accessControlContext +
'}'; '}';
} }
Expand Down Expand Up @@ -242,8 +258,13 @@ public String toString() {
} }


/** /**
* <p>
* A {@link net.bytebuddy.dynamic.loading.ByteArrayClassLoader} which applies child-first semantics for the * A {@link net.bytebuddy.dynamic.loading.ByteArrayClassLoader} which applies child-first semantics for the
* given type definitions. * given type definitions.
* </p>
* <p>
* <b>Important</b>: Package definitions remain their parent-first semantics as loaded package definitions do not expose their class loaders.
* </p>
*/ */
public static class ChildFirst extends ByteArrayClassLoader { public static class ChildFirst extends ByteArrayClassLoader {


Expand All @@ -264,8 +285,9 @@ public static class ChildFirst extends ByteArrayClassLoader {
public ChildFirst(ClassLoader parent, public ChildFirst(ClassLoader parent,
Map<String, byte[]> typeDefinitions, Map<String, byte[]> typeDefinitions,
ProtectionDomain protectionDomain, ProtectionDomain protectionDomain,
PersistenceHandler persistenceHandler) { PersistenceHandler persistenceHandler,
super(parent, typeDefinitions, protectionDomain, persistenceHandler); PackageDefiner packageDefiner) {
super(parent, typeDefinitions, protectionDomain, persistenceHandler, packageDefiner);
} }


@Override @Override
Expand All @@ -275,15 +297,24 @@ protected synchronized Class<?> loadClass(String name, boolean resolve) throws C
return type; return type;
} }
try { try {
type = findClass(name); try {
type = AccessController.doPrivileged(new ClassLoadingAction(name), accessControlContext);
} catch (PrivilegedActionException exception) {
Throwable cause = exception.getCause();
if (cause instanceof ClassNotFoundException) {
throw (ClassNotFoundException) cause;
} else {
throw new IllegalStateException("Could not load class " + name, cause);
}
}
if (resolve) { if (resolve) {
resolveClass(type); resolveClass(type);
} }
return type; return type;
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException exception) {
// If an unknown class is loaded, this implementation causes the findClass method of this instance // If an unknown class is loaded, this implementation causes the findClass method of this instance
// to be triggered twice. This is however of minor importance because this would result in a // to be triggered twice. This is however of minor importance because this would result in a
// ClassNotFoundException which is rather uncommon. // ClassNotFoundException what does not alter the outcome.
return super.loadClass(name, resolve); return super.loadClass(name, resolve);
} }
} }
Expand Down Expand Up @@ -332,6 +363,7 @@ public String toString() {
", typeDefinitions=" + typeDefinitions + ", typeDefinitions=" + typeDefinitions +
", protectionDomain=" + protectionDomain + ", protectionDomain=" + protectionDomain +
", persistenceHandler=" + persistenceHandler + ", persistenceHandler=" + persistenceHandler +
", packageDefiner=" + packageDefiner +
", accessControlContext=" + accessControlContext + ", accessControlContext=" + accessControlContext +
'}'; '}';
} }
Expand All @@ -340,7 +372,7 @@ public String toString() {
/** /**
* A class loading action is responsible to perform the loading of a class in a privileged security context. * A class loading action is responsible to perform the loading of a class in a privileged security context.
*/ */
private class ClassLoadingAction implements PrivilegedExceptionAction<Class<?>> { protected class ClassLoadingAction implements PrivilegedExceptionAction<Class<?>> {


/** /**
* A convenience index referencing the beginning of an array to improve code readability. * A convenience index referencing the beginning of an array to improve code readability.
Expand All @@ -350,33 +382,46 @@ private class ClassLoadingAction implements PrivilegedExceptionAction<Class<?>>
/** /**
* The name of the type to be loaded. * The name of the type to be loaded.
*/ */
private final String name; private final String typeName;


/** /**
* Creates a new class loading action. * Creates a new class loading action.
* *
* @param name The name of the type to be loaded. * @param typeName The name of the type to be loaded.
*/ */
private ClassLoadingAction(String name) { protected ClassLoadingAction(String typeName) {
this.name = name; this.typeName = typeName;
} }


@Override @Override
public Class<?> run() throws ClassNotFoundException { public Class<?> run() throws ClassNotFoundException, IOException {
byte[] javaType = persistenceHandler.lookup(name, typeDefinitions); byte[] javaType = persistenceHandler.lookup(typeName, typeDefinitions);
if (javaType != null) { if (javaType != null) {
int packageIndex = name.lastIndexOf('.'); int packageIndex = typeName.lastIndexOf('.');
if (packageIndex != -1 && getPackage(name.substring(0, packageIndex)) == null) { if (packageIndex != -1 && getPackage(typeName.substring(0, packageIndex)) == null) {
definePackage(name.substring(0, packageIndex), null, null, null, null, null, null, null); String packageName = typeName.substring(0, packageIndex);
PackageDefiner.Definition definition = packageDefiner.define(packageName,
ByteArrayClassLoader.this,
typeName.substring(packageIndex + 1));
if (definition.isDefined()) {
definePackage(packageName,
definition.getSpecificationTitle(),
definition.getSpecificationVersion(),
definition.getSpecificationVendor(),
definition.getImplementationTitle(),
definition.getImplementationVersion(),
definition.getImplementationVendor(),
definition.getSealBase());
}
} }
return defineClass(name, javaType, FROM_BEGINNING, javaType.length, protectionDomain); return defineClass(typeName, javaType, FROM_BEGINNING, javaType.length, protectionDomain);
} }
throw new ClassNotFoundException(name); throw new ClassNotFoundException(typeName);
} }


@Override @Override
public String toString() { public String toString() {
return "ByteArrayClassLoader.ClassLoadingAction{classLoader=" + ByteArrayClassLoader.this + ", name='" + name + "'}"; return "ByteArrayClassLoader.ClassLoadingAction{classLoader=" + ByteArrayClassLoader.this + ", typeName='" + typeName + "'}";
} }
} }
} }

0 comments on commit 92be204

Please sign in to comment.