Skip to content

Commit

Permalink
Reused Nexus accessor from agent builder.
Browse files Browse the repository at this point in the history
  • Loading branch information
raphw committed Jul 5, 2016
1 parent 4e9d827 commit 5326e33
Show file tree
Hide file tree
Showing 7 changed files with 564 additions and 125 deletions.
Expand Up @@ -769,6 +769,12 @@ interface Builder<T> {
* <p> * <p>
* Note that the specified definition does never apply for methods that are explicitly ignored. * Note that the specified definition does never apply for methods that are explicitly ignored.
* </p> * </p>
* <p>
* <b>Important</b>: It is possible to instrument the dynamic type's initializer. Depending on the used {@link TypeResolver},
* the type initializer might be run <b>before</b> Byte Buddy could apply any {@link LoadedTypeInitializer}s which are
* responsible for preparing the instrumented type prior to the initializer's execution. For preparing the type prior to
* executing the initializer, an {@link net.bytebuddy.dynamic.TypeResolver.Active} resolver must be chosen.
* </p>
* *
* @param matcher The matcher that determines what methods or constructors are affected by the subsequent specification. * @param matcher The matcher that determines what methods or constructors are affected by the subsequent specification.
* @return A builder that allows for changing a method's or constructor's definition. * @return A builder that allows for changing a method's or constructor's definition.
Expand All @@ -795,6 +801,12 @@ interface Builder<T> {
* <p> * <p>
* Note that the specified definition does never apply for methods that are explicitly ignored. * Note that the specified definition does never apply for methods that are explicitly ignored.
* </p> * </p>
* <p>
* <b>Important</b>: It is possible to instrument the dynamic type's initializer. Depending on the used {@link TypeResolver},
* the type initializer might be run <b>before</b> Byte Buddy could apply any {@link LoadedTypeInitializer}s which are
* responsible for preparing the instrumented type prior to the initializer's execution. For preparing the type prior to
* executing the initializer, an {@link net.bytebuddy.dynamic.TypeResolver.Active} resolver must be chosen.
* </p>
* *
* @param matcher The matcher that determines what declared methods or constructors are affected by the subsequent specification. * @param matcher The matcher that determines what declared methods or constructors are affected by the subsequent specification.
* @return A builder that allows for changing a method's or constructor's definition. * @return A builder that allows for changing a method's or constructor's definition.
Expand All @@ -810,21 +822,53 @@ interface Builder<T> {
* Supplying a type pool only makes sense if custom byte code is created by adding a custom {@link AsmVisitorWrapper} where ASM might be * Supplying a type pool only makes sense if custom byte code is created by adding a custom {@link AsmVisitorWrapper} where ASM might be
* required to compute stack map frames by processing information over any mentioned type's class hierarchy. * required to compute stack map frames by processing information over any mentioned type's class hierarchy.
* </p> * </p>
* <p>
* The dynamic type is initialized using a {@link net.bytebuddy.dynamic.TypeResolver.Passive} strategy. Using this strategy, no
* {@link LoadedTypeInitializer} is run during the execution of the type's initializer such that no {@link Implementation} used for
* executing the initializer must rely on such an initializer.
* </p>
* *
* @return An unloaded dynamic type representing the type specified by this builder. * @return An unloaded dynamic type representing the type specified by this builder.
*/ */
DynamicType.Unloaded<T> make(); DynamicType.Unloaded<T> make();


/**
* <p>
* Creates the dynamic type this builder represents. If the specified dynamic type is not legal, an {@link IllegalStateException} is thrown.
* </p>
* <p>
* The dynamic type is initialized using a {@link net.bytebuddy.dynamic.TypeResolver.Passive} strategy. Using this strategy, no
* {@link LoadedTypeInitializer} is run during the execution of the type's initializer such that no {@link Implementation} used for
* executing the initializer must rely on such an initializer.
* </p>
*
* @param typeResolver The type resolver to use for the created type's initialization.
* @return An unloaded dynamic type representing the type specified by this builder.
*/
DynamicType.Unloaded<T> make(TypeResolver typeResolver); DynamicType.Unloaded<T> make(TypeResolver typeResolver);


/** /**
* <p>
* Creates the dynamic type this builder represents. If the specified dynamic type is not legal, an {@link IllegalStateException} is thrown. * Creates the dynamic type this builder represents. If the specified dynamic type is not legal, an {@link IllegalStateException} is thrown.
* </p>
* <p>
* The dynamic type is initialized using a {@link net.bytebuddy.dynamic.TypeResolver.Passive} strategy. Using this strategy, no
* {@link LoadedTypeInitializer} is run during the execution of the type's initializer such that no {@link Implementation} used for
* executing the initializer must rely on such an initializer.
* </p>
* *
* @param typePool A type pool that is used for computing stack map frames by the underlying class writer, if required. * @param typePool A type pool that is used for computing stack map frames by the underlying class writer, if required.
* @return An unloaded dynamic type representing the type specified by this builder. * @return An unloaded dynamic type representing the type specified by this builder.
*/ */
DynamicType.Unloaded<T> make(TypePool typePool); DynamicType.Unloaded<T> make(TypePool typePool);


/**
* Creates the dynamic type this builder represents. If the specified dynamic type is not legal, an {@link IllegalStateException} is thrown.
*
* @param typeResolver The type resolver to use for the created type's initialization.
* @param typePool A type pool that is used for computing stack map frames by the underlying class writer, if required.
* @return An unloaded dynamic type representing the type specified by this builder.
*/
DynamicType.Unloaded<T> make(TypeResolver typeResolver, TypePool typePool); DynamicType.Unloaded<T> make(TypeResolver typeResolver, TypePool typePool);


/** /**
Expand Down Expand Up @@ -4371,6 +4415,9 @@ public String toString() {
*/ */
public static class Unloaded<T> extends Default implements DynamicType.Unloaded<T> { public static class Unloaded<T> extends Default implements DynamicType.Unloaded<T> {


/**
* The type resolver to use for initializing the dynamic type.
*/
private final TypeResolver.Resolved typeResolver; private final TypeResolver.Resolved typeResolver;


/** /**
Expand All @@ -4380,6 +4427,7 @@ public static class Unloaded<T> extends Default implements DynamicType.Unloaded<
* @param binaryRepresentation An array of byte of the binary representation of this dynamic type. * @param binaryRepresentation An array of byte of the binary representation of this dynamic type.
* @param loadedTypeInitializer The type initializer of this dynamic type. * @param loadedTypeInitializer The type initializer of this dynamic type.
* @param auxiliaryTypes The auxiliary types that are required for this dynamic type. * @param auxiliaryTypes The auxiliary types that are required for this dynamic type.
* @param typeResolver The type resolver to use for initializing the dynamic type.
*/ */
public Unloaded(TypeDescription typeDescription, public Unloaded(TypeDescription typeDescription,
byte[] binaryRepresentation, byte[] binaryRepresentation,
Expand Down
181 changes: 180 additions & 1 deletion byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/TypeResolver.java
Expand Up @@ -26,19 +26,52 @@
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import static net.bytebuddy.matcher.ElementMatchers.takesArguments;


/**
* A type resolver is responsible for loading a class and for initializing its {@link LoadedTypeInitializer}s.
*/
public interface TypeResolver { public interface TypeResolver {


/**
* Resolves a type resolver for actual application.
*
* @return A resolved version of this type resolver.
*/
Resolved resolve(); Resolved resolve();


/**
* A resolved {@link TypeResolver}.
*/
interface Resolved { interface Resolved {


/**
* Injects a type initializer into the supplied type initializer, if applicable. This way, a type resolver
* is capable of injecting code into the generated class's initializer to inline the initialization.
*
* @param typeInitializer The type initializer to potentially expend.
* @return A type initializer to apply for performing the represented type resolution.
*/
TypeInitializer injectedInto(TypeInitializer typeInitializer); TypeInitializer injectedInto(TypeInitializer typeInitializer);


/**
* Loads and initializes a dynamic type.
*
* @param dynamicType The dynamic type to initialize.
* @param classLoader The class loader to use.
* @param classLoadingStrategy The class loading strategy to use.
* @return A map of all type descriptions mapped to their representation as a loaded class.
*/
Map<TypeDescription, Class<?>> initialize(DynamicType dynamicType, ClassLoader classLoader, ClassLoadingStrategy classLoadingStrategy); Map<TypeDescription, Class<?>> initialize(DynamicType dynamicType, ClassLoader classLoader, ClassLoadingStrategy classLoadingStrategy);
} }


/**
* A type resolver that applies all {@link LoadedTypeInitializer} after class loading using reflection. This implies that the initializers
* are executed <b>after</b> a type initializer is executed.
*/
enum Passive implements TypeResolver, Resolved { enum Passive implements TypeResolver, Resolved {


/**
* The singleton instance.
*/
INSTANCE; INSTANCE;


@Override @Override
Expand All @@ -59,12 +92,27 @@ public Map<TypeDescription, Class<?>> initialize(DynamicType dynamicType, ClassL
} }
return new HashMap<TypeDescription, Class<?>>(types); return new HashMap<TypeDescription, Class<?>>(types);
} }

@Override
public String toString() {
return "TypeResolver.Passive." + name();
}
} }


/**
* A type resolver that applies all {@link LoadedTypeInitializer} as a part of class loading using reflection. This implies that the initializers
* are executed <b>before</b> (as a first action of) a type initializer is executed.
*/
enum Active implements TypeResolver { enum Active implements TypeResolver {


/**
* The singleton instance.
*/
INSTANCE; INSTANCE;


/**
* The dispatcher to use.
*/
private final Dispatcher dispatcher; private final Dispatcher dispatcher;


/** /**
Expand Down Expand Up @@ -131,12 +179,25 @@ public TypeResolver.Resolved resolve() {
return new Resolved(new Random().nextInt()); return new Resolved(new Random().nextInt());
} }


/**
* Registers a loaded type initializer in Byte Buddy's {@link Nexus} which is injected into the system class loader.
*
* @param name The binary name of the class.
* @param classLoader The class's class loader.
* @param identification The id used for identifying the loaded type initializer that was added to the {@link Nexus}.
* @param loadedTypeInitializer The loaded type initializer to make available via the {@link Nexus}.
*/
public void register(String name, ClassLoader classLoader, int identification, LoadedTypeInitializer loadedTypeInitializer) { public void register(String name, ClassLoader classLoader, int identification, LoadedTypeInitializer loadedTypeInitializer) {
if (loadedTypeInitializer.isAlive()) { if (loadedTypeInitializer.isAlive()) {
dispatcher.register(name, classLoader, identification, loadedTypeInitializer); dispatcher.register(name, classLoader, identification, loadedTypeInitializer);
} }
} }


@Override
public String toString() {
return "TypeResolver.Active." + name();
}

/** /**
* A dispatcher for registering type initializers in the {@link Nexus}. * A dispatcher for registering type initializers in the {@link Nexus}.
*/ */
Expand Down Expand Up @@ -197,6 +258,13 @@ public boolean equals(Object other) {
public int hashCode() { public int hashCode() {
return registration.hashCode(); return registration.hashCode();
} }

@Override
public String toString() {
return "TypeResolver.Active.Dispatcher.Available{" +
"registration=" + registration +
'}';
}
} }


/** /**
Expand Down Expand Up @@ -233,13 +301,31 @@ public boolean equals(Object other) {
public int hashCode() { public int hashCode() {
return exception.hashCode(); return exception.hashCode();
} }

@Override
public String toString() {
return "TypeResolver.Active.Dispatcher.Unavailable{" +
"exception=" + exception +
'}';
}
} }
} }


/**
* A resolved version of an active type resolver.
*/
protected static class Resolved implements TypeResolver.Resolved { protected static class Resolved implements TypeResolver.Resolved {


/**
* The id used for identifying the loaded type initializer that was added to the {@link Nexus}.
*/
private final int identification; private final int identification;


/**
* Creates a new resolved active type resolver.
*
* @param identification The id used for identifying the loaded type initializer that was added to the {@link Nexus}.
*/
protected Resolved(int identification) { protected Resolved(int identification) {
this.identification = identification; this.identification = identification;
} }
Expand All @@ -260,12 +346,43 @@ public Map<TypeDescription, Class<?>> initialize(DynamicType dynamicType, ClassL
} }
return types; return types;
} }

@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
Resolved resolved = (Resolved) object;
return identification == resolved.identification;
}

@Override
public int hashCode() {
return identification;
}

@Override
public String toString() {
return "TypeResolver.Active.Resolved{" +
"identification=" + identification +
'}';
}
} }


/**
* An initialization appender that looks up a loaded type initializer from Byte Buddy's {@link Nexus}.
*/
public static class InitializationAppender implements ByteCodeAppender { public static class InitializationAppender implements ByteCodeAppender {


/**
* The id used for identifying the loaded type initializer that was added to the {@link Nexus}.
*/
private final int identification; private final int identification;


/**
* Creates a new initialization appender.
*
* @param identification The id used for identifying the loaded type initializer that was added to the {@link Nexus}.
*/
public InitializationAppender(int identification) { public InitializationAppender(int identification) {
this.identification = identification; this.identification = identification;
} }
Expand Down Expand Up @@ -293,11 +410,37 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa
Removal.SINGLE Removal.SINGLE
)).apply(methodVisitor, implementationContext, instrumentedMethod); )).apply(methodVisitor, implementationContext, instrumentedMethod);
} }

@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
InitializationAppender that = (InitializationAppender) object;
return identification == that.identification;
}

@Override
public int hashCode() {
return identification;
}

@Override
public String toString() {
return "TypeResolver.Active.InitializationAppender{" +
"identification=" + identification +
'}';
}
} }
} }


enum Disabled implements TypeResolver, Resolved { /**
* A type resolver that does not apply any {@link LoadedTypeInitializer}s but only loads all types.
*/
enum Lazy implements TypeResolver, Resolved {


/**
* The singleton instance.
*/
INSTANCE; INSTANCE;


@Override @Override
Expand All @@ -314,5 +457,41 @@ public TypeInitializer injectedInto(TypeInitializer typeInitializer) {
public Map<TypeDescription, Class<?>> initialize(DynamicType dynamicType, ClassLoader classLoader, ClassLoadingStrategy classLoadingStrategy) { public Map<TypeDescription, Class<?>> initialize(DynamicType dynamicType, ClassLoader classLoader, ClassLoadingStrategy classLoadingStrategy) {
return classLoadingStrategy.load(classLoader, dynamicType.getAllTypes()); return classLoadingStrategy.load(classLoader, dynamicType.getAllTypes());
} }

@Override
public String toString() {
return "TypeResolver.Lazy." + name();
}
}

/**
* A type resolver that does not allow for explicit loading of a class and that does not inject any code into the type initializer.
*/
enum Disabled implements TypeResolver, Resolved {

/**
* The singleton instance.
*/
INSTANCE;

@Override
public Resolved resolve() {
return this;
}

@Override
public TypeInitializer injectedInto(TypeInitializer typeInitializer) {
return typeInitializer;
}

@Override
public Map<TypeDescription, Class<?>> initialize(DynamicType dynamicType, ClassLoader classLoader, ClassLoadingStrategy classLoadingStrategy) {
throw new IllegalStateException("Cannot initialize a dynamic type for a disabled type resolver");
}

@Override
public String toString() {
return "TypeResolver.Disabled." + name();
}
} }
} }
Expand Up @@ -59,6 +59,7 @@ public interface TypeWriter<T> {
/** /**
* Creates the dynamic type that is described by this type writer. * Creates the dynamic type that is described by this type writer.
* *
* @param typeResolver The type resolver to use.
* @return An unloaded dynamic type that describes the created type. * @return An unloaded dynamic type that describes the created type.
*/ */
DynamicType.Unloaded<T> make(TypeResolver.Resolved typeResolver); DynamicType.Unloaded<T> make(TypeResolver.Resolved typeResolver);
Expand Down

0 comments on commit 5326e33

Please sign in to comment.