package net.bytebuddy.dynamic.scaffold;
import lombok.EqualsAndHashCode;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.attribute.AnnotationValueFilter;
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
/**
* A type initializer is responsible for defining a type's static initialization block.
*/
public interface TypeInitializer extends ByteCodeAppender {
/**
* Indicates if this type initializer is defined.
*
* @return {@code true} if this type initializer is defined.
*/
boolean isDefined();
/**
* Expands this type initializer with another byte code appender. For this to be possible, this type initializer must
* be defined.
*
* @param byteCodeAppender The byte code appender to apply as the type initializer.
* @return A defined type initializer.
*/
TypeInitializer expandWith(ByteCodeAppender byteCodeAppender);
/**
* Creates a method pool record that applies this type initializer while preserving the record that was supplied.
*
* @param record The record to wrap.
* @return A new record that represents the supplied record while also executing this type initializer.
*/
TypeWriter.MethodPool.Record wrap(TypeWriter.MethodPool.Record record);
/**
* A drain for writing a type initializer.
*/
interface Drain {
/**
* Applies the drain.
*
* @param classVisitor The class visitor to apply the initializer to.
* @param typeInitializer The type initializer to write.
* @param implementationContext The corresponding implementation context.
*/
void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext);
/**
* A default implementation of a type initializer drain that creates a initializer method.
*/
@EqualsAndHashCode
class Default implements Drain {
/**
* The instrumented type.
*/
protected final TypeDescription instrumentedType;
/**
* The method pool to use.
*/
protected final TypeWriter.MethodPool methodPool;
/**
* The annotation value filter factory to use.
*/
protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
/**
* Creates a new default type initializer drain.
*
* @param instrumentedType The instrumented type.
* @param methodPool The method pool to use.
* @param annotationValueFilterFactory The annotation value filter factory to use.
*/
public Default(TypeDescription instrumentedType,
TypeWriter.MethodPool methodPool,
AnnotationValueFilter.Factory annotationValueFilterFactory) {
this.instrumentedType = instrumentedType;
this.methodPool = methodPool;
this.annotationValueFilterFactory = annotationValueFilterFactory;
}
@Override
public void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext) {
typeInitializer.wrap(methodPool.target(new MethodDescription.Latent.TypeInitializer(instrumentedType))).apply(classVisitor,
implementationContext,
annotationValueFilterFactory);
}
}
}
/**
* Canonical implementation of a non-defined type initializer.
*/
enum None implements TypeInitializer {
/**
* The singleton instance.
*/
INSTANCE;
@Override
public boolean isDefined() {
return false;
}
@Override
public TypeInitializer expandWith(ByteCodeAppender byteCodeAppenderFactory) {
return new TypeInitializer.Simple(byteCodeAppenderFactory);
}
@Override
public TypeWriter.MethodPool.Record wrap(TypeWriter.MethodPool.Record record) {
return record;
}
@Override
public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
return new Size(0, 0);
}
}
/**
* A simple, defined type initializer that executes a given {@link ByteCodeAppender}.
*/
@EqualsAndHashCode
class Simple implements TypeInitializer {
/**
* The byte code appender to apply as the type initializer.
*/
private final ByteCodeAppender byteCodeAppender;
/**
* Creates a new simple type initializer.
*
* @param byteCodeAppender The byte code appender to apply as the type initializer.
*/
public Simple(ByteCodeAppender byteCodeAppender) {
this.byteCodeAppender = byteCodeAppender;
}
@Override
public boolean isDefined() {
return true;
}
@Override
public TypeInitializer expandWith(ByteCodeAppender byteCodeAppender) {
return new TypeInitializer.Simple(new Compound(this.byteCodeAppender, byteCodeAppender));
}
@Override
public TypeWriter.MethodPool.Record wrap(TypeWriter.MethodPool.Record record) {
return record.prepend(byteCodeAppender);
}
@Override
public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
return byteCodeAppender.apply(methodVisitor, implementationContext, instrumentedMethod);
}
}
}