// Generated by delombok at Sun Feb 26 12:31:38 KST 2017
package scouter.bytebuddy.agent.builder;
import scouter.bytebuddy.description.type.TypeDescription;
import scouter.bytebuddy.dynamic.ClassFileLocator;
import scouter.bytebuddy.dynamic.loading.ClassInjector;
import java.lang.instrument.ClassFileTransformer;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* This class serves as a dispatcher for creating lambda expression objects when Byte Buddy is configured to instrument the
* {@code java.lang.invoke.LambdaMetafactory}. For this purpose, this class is injected into the class path to serve as a VM-global
* singleton and for becoming reachable from the JVM's meta factory. This class keeps a reference to all registered transformers which need
* to be explicitly deregistered in order to avoid a memory leak.
*/
public class LambdaFactory {
/**
* The name of the field to access.
*/
private static final String FIELD_NAME = "CLASS_FILE_TRANSFORMERS";
/**
* A mapping of all registered class file transformers and their lambda factories, linked in their application order.
* This field <b>must not</b> be accessed directly but only by reading this class from the system class loader.
*/
public static final Map<ClassFileTransformer, LambdaFactory> CLASS_FILE_TRANSFORMERS = new ConcurrentHashMap<ClassFileTransformer, LambdaFactory>();
/**
* The target instance that is a factory for creating lambdas.
*/
private final Object target;
/**
* The dispatcher method to invoke for creating a new lambda instance.
*/
private final Method dispatcher;
/**
* Creates a new lambda factory.
*
* @param target The target instance that is a factory for creating lambdas.
* @param dispatcher The dispatcher method to invoke for creating a new lambda instance.
*/
public LambdaFactory(Object target, Method dispatcher) {
this.target = target;
this.dispatcher = dispatcher;
}
/**
* Registers a class file transformer together with a factory for creating a lambda expression. It is possible to call this method independently
* of the class loader's context as the supplied injector makes sure that the manipulated collection is the one that is held by the system class
* loader.
*
* @param classFileTransformer The class file transformer to register.
* @param classFileFactory The lambda class file factory to use. This factory must define a visible instance method with the signature
* {@code byte[] make(Object, String, Object, Object, Object, Object, boolean, List, List, Collection}. The arguments provided
* are the invokedynamic call site's lookup object, the lambda method's name, the factory method's type, the lambda method's
* type, the target method's handle, the specialized method type of the lambda expression, a boolean to indicate
* serializability, a list of marker interfaces, a list of additional bridges and a collection of class file transformers to
* apply.
* @return {@code true} if this is the first registered transformer. This indicates that the {@code LambdaMetafactory} must be instrumented to delegate
* to this alternative factory.
*/
@SuppressWarnings("all")
public static boolean register(ClassFileTransformer classFileTransformer, Object classFileFactory) {
try {
TypeDescription typeDescription = new TypeDescription.ForLoadedType(LambdaFactory.class);
Class<?> lambdaFactory = ClassInjector.UsingReflection.ofSystemClassLoader().inject(Collections.singletonMap(typeDescription, ClassFileLocator.ForClassLoader.read(LambdaFactory.class).resolve())).get(typeDescription);
@SuppressWarnings("unchecked")
Map<ClassFileTransformer, Object> classFileTransformers = (Map<ClassFileTransformer, Object>) lambdaFactory.getField(FIELD_NAME).get(null);
synchronized (classFileTransformers) {
try {
return classFileTransformers.isEmpty();
} finally {
classFileTransformers.put(classFileTransformer, lambdaFactory.getConstructor(Object.class, Method.class).newInstance(classFileFactory, classFileFactory.getClass().getMethod("make", Object.class, String.class, Object.class, Object.class, Object.class, Object.class, boolean.class, List.class, List.class, Collection.class)));
}
}
} catch (RuntimeException exception) {
throw exception;
} catch (Exception exception) {
throw new IllegalStateException("Could not register class file transformer", exception);
}
}
/**
* Releases a class file transformer.
*
* @param classFileTransformer The class file transformer to release.
* @return {@code true} if the removed transformer was the last class file transformer registered. This indicates that the {@code LambdaMetafactory} must
* be instrumented to no longer delegate to this alternative factory.
*/
@SuppressWarnings("all")
public static boolean release(ClassFileTransformer classFileTransformer) {
try {
@SuppressWarnings("unchecked")
Map<ClassFileTransformer, ?> classFileTransformers = (Map<ClassFileTransformer, ?>) ClassLoader.getSystemClassLoader().loadClass(LambdaFactory.class.getName()).getField(FIELD_NAME).get(null);
synchronized (classFileTransformers) {
return classFileTransformers.remove(classFileTransformer) != null && classFileTransformers.isEmpty();
}
} catch (RuntimeException exception) {
throw exception;
} catch (Exception exception) {
throw new IllegalStateException("Could not release class file transformer", exception);
}
}
/**
* Applies this lambda meta factory.
*
* @param caller A lookup context representing the creating class of this lambda expression.
* @param invokedName The name of the lambda expression's represented method.
* @param invokedType The type of the lambda expression's factory method.
* @param samMethodType The type of the lambda expression's represented method.
* @param implMethod A handle representing the target of the lambda expression's method.
* @param instantiatedMethodType A specialization of the type of the lambda expression's represented method.
* @param serializable {@code true} if the lambda expression should be serializable.
* @param markerInterfaces A list of interfaces for the lambda expression to represent.
* @param additionalBridges A list of additional bridge methods to be implemented by the lambda expression.
* @param classFileTransformers A collection of class file transformers to apply when creating the class.
* @return A binary representation of the transformed class file.
*/
private byte[] invoke(Object caller, String invokedName, Object invokedType, Object samMethodType, Object implMethod, Object instantiatedMethodType, boolean serializable, List<Class<?>> markerInterfaces, List<?> additionalBridges, Collection<ClassFileTransformer> classFileTransformers) {
try {
return (byte[]) dispatcher.invoke(target, caller, invokedName, invokedType, samMethodType, implMethod, instantiatedMethodType, serializable, markerInterfaces, additionalBridges, classFileTransformers);
} catch (RuntimeException exception) {
throw exception;
} catch (Exception exception) {
throw new IllegalStateException("Cannot create class for lambda expression", exception);
}
}
/**
* Dispatches the creation of a new class representing a class file.
*
* @param caller A lookup context representing the creating class of this lambda expression.
* @param invokedName The name of the lambda expression's represented method.
* @param invokedType The type of the lambda expression's factory method.
* @param samMethodType The type of the lambda expression's represented method.
* @param implMethod A handle representing the target of the lambda expression's method.
* @param instantiatedMethodType A specialization of the type of the lambda expression's represented method.
* @param serializable {@code true} if the lambda expression should be serializable.
* @param markerInterfaces A list of interfaces for the lambda expression to represent.
* @param additionalBridges A list of additional bridge methods to be implemented by the lambda expression.
* @return A binary representation of the transformed class file.
*/
public static byte[] make(Object caller, String invokedName, Object invokedType, Object samMethodType, Object implMethod, Object instantiatedMethodType, boolean serializable, List<Class<?>> markerInterfaces, List<?> additionalBridges) {
return CLASS_FILE_TRANSFORMERS.values().iterator().next()
.invoke(caller,
invokedName,
invokedType,
samMethodType,
implMethod,
instantiatedMethodType,
serializable,
markerInterfaces,
additionalBridges,
CLASS_FILE_TRANSFORMERS.keySet());
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof LambdaFactory)) return false;
final LambdaFactory other = (LambdaFactory) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$target = this.target;
final java.lang.Object other$target = other.target;
if (this$target == null ? other$target != null : !this$target.equals(other$target)) return false;
final java.lang.Object this$dispatcher = this.dispatcher;
final java.lang.Object other$dispatcher = other.dispatcher;
if (this$dispatcher == null ? other$dispatcher != null : !this$dispatcher.equals(other$dispatcher)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof LambdaFactory;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $target = this.target;
result = result * PRIME + ($target == null ? 43 : $target.hashCode());
final java.lang.Object $dispatcher = this.dispatcher;
result = result * PRIME + ($dispatcher == null ? 43 : $dispatcher.hashCode());
return result;
}
}