object ClassFileFactory
Provides helper methods to facilitate the generation of classes. In particular, functionality to create transparent proxy classes is provided.
- Source
- ClassFileFactory.scala
- Alphabetic
- By Inheritance
- ClassFileFactory
- AnyRef
- Any
- Hide All
- Show All
- Public
- Protected
Value Members
- final def !=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- final def ##: Int
- Definition Classes
- AnyRef → Any
- final def ==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- final val AlternativeFactoryMethodName: String("$createInstance")
Alternative name for the factory method of proxy classes created by the Proxy method.
Alternative name for the factory method of proxy classes created by the Proxy method. This name is only used if the proxified method's name is equal to DefaultFactoryMethodName.
- final val DefaultFactoryMethodName: String("$newInstance")
This is the default name for the factory method of a proxy class that is created by the Proxy method.
This is the default name for the factory method of a proxy class that is created by the Proxy method. If the name of the method to be proxified is equal to this name, AlternativeFactoryMethodName is used instead.
- def DeserializeLambdaProxy(definingType: TypeDeclaration, bootstrapArguments: BootstrapArguments, staticMethodName: String): ClassFile
- def Proxy(caller: ObjectType, callerIsInterface: Boolean, definingType: TypeDeclaration, methodName: String, methodDescriptor: MethodDescriptor, receiverType: ObjectType, receiverIsInterface: Boolean, implMethod: MethodCallMethodHandle, invocationInstruction: Opcode, samMethodType: MethodDescriptor, bridgeMethodDescriptors: MethodDescriptors): ClassFile
Creates a class that acts as a proxy for the specified class.
Creates a class that acts as a proxy for the specified class. The proxy implements a single method – e.g., as defined by a so-called "Functional Interface" - that calls the specified method; creating a proxy for
java.lang.Object
's methods is not supported. Additionally, further marker interfaces (e.g.,java.io.Serializable
) may be implemented.The generated class uses the following template:
class <definingType.objectType> extends <definingType.theSuperclassType> implements <definingType.theSuperinterfaceTypes> { private final <ReceiverType> receiver; // possible additional fields for static parameters public "<init>"( <ReceiverType> receiver) { // the constructor this.receiver = receiver; } public <methodDescriptor.returnType> <methodName> <methodDescriptor.parameterTypes>{ return/*<= if the return type is not void*/ this.receiver.<receiverMethodName>(<parameters>) } // possibly multiple bridge methods (multiple only in case of altLambdaMetaFactory usages) }
The class, the constructor and the method are public. The field which holds the receiver object is private and final unless the receiver method is static. In this case no receiver field is generated and the constructor does not take an argument of the receiver's type.
In addition to the receiver field, additional fields holding static parameters are created if all parameters found in
methodDescriptor
are present, in the same order, at the end ofreceiverMethodDescriptor
's parameters, butreceiverMethodDescriptor
has more parameters that precede the parameters found inmethodDescriptor
.E.g., given the following two descriptors:
val methodDescriptor = MethodDescriptor(IntegerType, IntegerType) val receiverMethodDescriptor = MethodDescriptor(IndexedSeq(DoubleType, IntegerType), IntegerType)
one additional field and constructor parameter of type
double
will be created. This case occurs for example with Java 8 lambda expressions that capture local variables, which are prepended to the regular parameter list.If any of the parameters or the return type of
methodDescriptor
are generic types, the generated proxy will need to create a bridge method to be valid. Therefore, in these cases,bridgeMethodDescriptor
must be specified. It must be identical tomethodDescriptor
except for all occurrences of generic types, which must be replaced withObjectType.Object
. For example, consider the Java interfacejava.util.Comparator
that defines the generic typeT
and uses it in itsint compare(T, T)
method. This would require a bridge methodint compare(Object, Object)
. The appropriate method descriptors for, for example,Comparator<String>
would be:// Uses "String" methodDescriptor = MethodDescriptor(IndexedSeq(ObjectType.String, ObjectType.String), IntegerType) // Uses "Object" bridgeMethodDescriptor = MethodDescriptor(IndexedSeq(ObjectType.Object, ObjectType.Object), IntegerType)
The created class will always have its synthetic access flag set, as well as the VirtualTypeFlag attribute.
- definingType
The defining type; if the type is
Serializable
, the interface has to be a direct super interface.- invocationInstruction
the opcode of the invocation instruction (
INVOKESPECIAL.opcode
,INVOKEVIRTUAL.opcode
,INVOKESTATIC.opcode
,INVOKEINTERFACE.opcode
) used to call call the method on the receiver.
- Note
The used class file version is 52. (StackMapTables are, however, still not required because the code contains no relevant control-flow.)
,It is expected that
methodDescriptor
andreceiverMethodDescriptor
are "compatible", i.e., it would be possible to have the method described bymethodDescriptor
forward toreceiverMethodDescriptor
. This requires that for their return types, one of the following statements holds true: -methodDescriptor
's return type is VoidType (so no returning is necessary) -receiverMethodDescriptor
's return type is assignable tomethodDescriptor
's (e.g., a "smaller" numerical type, (un)boxable, a subtype, etc) -receiverMethodDescriptor
returnsObject
: in this case, we assume thatObject
stands for "generic return type" and expect the receiver method to return an object of a type compatible to the forwarder method's return type Additionally, the parameter lists must satisfy one of these conditions: - they are identical - the descriptors have the same numbers of parameters andmethodDescriptor
's parameter types can be widened/boxed/unboxed to matchreceiverMethodDescriptor
's parameter types -methodDescriptor
's first parameter is of the same type asreceiverType
, and the remaining parameters are compatible toreceiverMethodDescriptor
's entire parameter list (this is, effectively, an explicitthis
and occurs for example with references to instance methods: e.g.,String::isEmpty
, a zero argument method, could be turned into the Predicate methodtest(String)
) - the lastn
parameters ofreceiverMethodDescriptor
are identical to the parameters ofmethodDescriptor
, wheren = methodDescriptor.parametersCount
(this is the case if a lambda expression captures local variables) -receiverMethodDescriptor
's single parameter is of typeObject[]
(in this case,methodDescriptor
's arguments will be collected into anObject[]
prior to forwarding) Examples of compatible method descriptors are:// ------------- First Example methodDescriptor = MethodDescriptor(IntegerType, VoidType) receiverMethodDescriptor = MethodDescriptor(ObjectType.Integer, VoidType) // or MethodDescriptor(ObjectType.Object, ByteType) // ------------- Second Example methodDescriptor = MethodDescriptor(ObjectType.String, BooleanType) receiverMethodDescriptor = MethodDescriptor.JustReturnsBoolean // IF receiverType == ObjectType.String // ------------- Third Example methodDescriptor = MethodDescriptor(IndexedSeq(ByteType, ByteType, ObjectType.Integer), IntegerType) receiverMethodDescriptor = MethodDescriptor(ArrayType.ArrayOfObject, ObjectType.Object) // generic method // ------------- Fourth Example methodDescriptor = MethodDescriptor(IntegerType, LongType) receiverMethodDescriptor = MethodDescriptor(IndexedSeq(ByteType, ByteType, IntegerType), IntegerType)
- final val ReceiverFieldName: String("$receiver")
Name used to store the final receiver object in generated proxy classes.
- final def asInstanceOf[T0]: T0
- Definition Classes
- Any
- def callSuperDefaultConstructor(theSuperclassType: ObjectType): Array[Instruction]
Returns the instructions necessary to perform a call to the constructor of the given superclass.
- def clone(): AnyRef
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.CloneNotSupportedException]) @native() @IntrinsicCandidate()
- def cloneMethodSignature: MethodSignature
- def copyParametersToInstanceFields(declaringType: ObjectType, fields: FieldTemplates): Array[Instruction]
Creates an array of instructions that populates the given
fields
indeclaringType
from local variables (constructor parameters).Creates an array of instructions that populates the given
fields
indeclaringType
from local variables (constructor parameters).This method assumes that it creates instructions for a constructor whose parameter list matches the given
fields
in terms of order and field types.It further assumes that none of the
fields
provided as arguments are static fields, as it would make little sense to initialize static fields through the constructor. - def createBridgeMethod(methodName: String, bridgeMethodDescriptor: MethodDescriptor, targetMethodDescriptor: MethodDescriptor, targetMethodDeclaringType: ObjectType): MethodTemplate
Creates a bridge method using the given method descriptors, name, and type.
Creates a bridge method using the given method descriptors, name, and type.
The bridge method's parameter list and return type are dictated by
bridgeMethodDescriptor
. This method generates bytecode that invokes the method described bymethodName
andtargetMethodDescriptor
ondeclaringType
. If parameters need to be cast before invocation, the appropriate bytecode will be generated as well. - def createConstructor(definingType: TypeDeclaration, fields: FieldTemplates): MethodTemplate
Creates a public constructor that initializes the given fields.
Creates a public constructor that initializes the given fields.
For every
Field
infields
the constructor will have one parameter of the same type. The parameter list will have the same order asfields
. The generated constructor will call the superclass' default constructor; i.e., the typedefiningType.theSuperclassType
has to have a default constructor. Additionally, bytecode is generated to populate thefields
from the constructor arguments. - def createDeserializeLambdaProxy(caller: ObjectType, callerIsInterface: Boolean): MethodTemplate
Creates a static proxy method used by the
$deserializeLambda$
method.Creates a static proxy method used by the
$deserializeLambda$
method.- caller
The class where the lambda is implemented.
- callerIsInterface
true
if the class is an interface, false if not.- returns
The static proxy method relaying the
$deserializedLambda$
invocation to the actual class that implements the lambda.
- def createFactoryMethod(typeToCreate: ObjectType, fieldTypes: FieldTypes, factoryMethodName: String): MethodTemplate
Creates a factory method with the appropriate instructions to create and return an instance of
typeToCreate
.Creates a factory method with the appropriate instructions to create and return an instance of
typeToCreate
.typeToCreate
must have a constructor with a parameter list that exactly matchesfieldTypes
. It also must not define a method namedfactoryMethodName
with a parameter list matchingfieldTypes
.- See also
- def createField(accessFlags: Int = bi.ACC_PRIVATE.mask | bi.ACC_FINAL.mask, name: String, fieldType: FieldType, attributes: Attributes = NoAttributes): FieldTemplate
Creates a field of the specified type with the given name.
- def createWriteReplaceMethod(definingType: TypeDeclaration, methodName: String, samMethodType: MethodDescriptor, implMethod: MethodCallMethodHandle, instantiatedMethodType: MethodDescriptor, additionalFieldsForStaticParameters: FieldTemplates): MethodTemplate
Creates the
writeReplace
method for a lambda proxy class.Creates the
writeReplace
method for a lambda proxy class. It is used to create aSerializedLambda
object which holds the serialized lambda.The parameters of the SerializedLambda class map are as following: capturingClass = definingType functionalInterfaceClass = definingType.theSuperinterfaceTypes.head (This is the functional interface) functionalInterfaceMethodName = functionalInterfaceMethodName functionalInterfaceMethodSignature = samMethodType.parameterType implMethodKind = implMethod match to REF_ implClass = implMethod.receiverType implMethodName = implMethod.name implMethodSignature = implMethod.methodDescriptor instantiatedMethodType = instantiatedMethodType capturedArgs = methodDescriptor.parameterTypes (factoryParameters, fields in Proxy)
- definingType
The lambda proxyclass type.
- methodName
The name of the functional interface method.
- samMethodType
Includes the method signature for the functional interface method.
- implMethod
The lambda method inside the class defining the lambda.
- additionalFieldsForStaticParameters
The static fields that are put into the capturedArgs.
- returns
A SerializedLambda object containing all information to be able to serialize this lambda.
- See also
https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/SerializedLambda.html and https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/LambdaMetafactory.html#altMetafactory-java.lang.invoke.MethodHandles.Lookup-java.lang.String-java.lang.invoke.MethodType-java.lang.Object...-
- final def eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- def equals(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef → Any
- def equalsMethodSignature: MethodSignature
- def finalizeMethodSignature: MethodSignature
- final def getClass(): Class[_ <: AnyRef]
- Definition Classes
- AnyRef → Any
- Annotations
- @native() @IntrinsicCandidate()
- def hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @native() @IntrinsicCandidate()
- def hashCodeMethodSignature: MethodSignature
- final def isInstanceOf[T0]: Boolean
- Definition Classes
- Any
- def isNewInvokeSpecial(opcode: Opcode, methodName: String): Boolean
Returns true if the method invocation described by the given Opcode and method name is a "NewInvokeSpecial" invocation (i.e., a reference to a constructor, like so:
Object::new
). - def isVirtualMethodReference(opcode: Opcode, targetMethodDeclaringType: ObjectType, targetMethodDescriptor: MethodDescriptor, proxyInterfaceMethodDescriptor: MethodDescriptor): Boolean
Returns true if the given parameters identify a Java 8 method reference to an instance or interface method (i.e., a reference to a virtual method, like so:
ArrayList::size
orList::size
).Returns true if the given parameters identify a Java 8 method reference to an instance or interface method (i.e., a reference to a virtual method, like so:
ArrayList::size
orList::size
). In this case, the resulting functional interface's method has one parameter more than the referenced method because the referenced method's implicitthis
parameter becomes explicit. - final def ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- def nonFinalInterfaceOfObject(): Array[MethodSignature]
- final def notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native() @IntrinsicCandidate()
- final def notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native() @IntrinsicCandidate()
- def parameterForwardingInstructions(forwarderMethodDescriptor: MethodDescriptor, receiverMethodDescriptor: MethodDescriptor, variableOffset: Int, staticParameters: Seq[FieldTemplate], definingType: ObjectType): Array[Instruction]
Generates an array of instructions that fill the operand stack with all parameters required by
receiverMethodDescriptor
from the parameters ofcalledMethodDescriptor
.Generates an array of instructions that fill the operand stack with all parameters required by
receiverMethodDescriptor
from the parameters ofcalledMethodDescriptor
. For that reason, it is expected that both method descriptors have compatible parameter and return types: i.e., thatforwarderMethodDescriptor
's parameters can be widened or (un)boxed to fit intoreceiverMethodDescriptor
's parameters, and thatreceiverMethodDescriptor
's return type can be widened or (un)boxed to fit intoforwarderMethodDescriptor
's return type.If
receiverMethodDescriptor
has more parameters thanforwarderMethodDescriptor
, the missing parameters must be provided instaticParameters
. - def proxyMethod(definingType: ObjectType, methodName: String, methodDescriptor: MethodDescriptor, staticParameters: Seq[FieldTemplate], receiverType: ObjectType, receiverIsInterface: Boolean, implMethod: MethodCallMethodHandle, invocationInstruction: Opcode): MethodTemplate
Creates a proxy method with name
methodName
and descriptormethodDescriptor
and the bytecode instructions to execute the methodreceiverMethod
inreceiverType
.Creates a proxy method with name
methodName
and descriptormethodDescriptor
and the bytecode instructions to execute the methodreceiverMethod
inreceiverType
.The
methodDescriptor
s have to be identical in terms of parameter types and have to be compatible w.r.t. the return type. - def returnAndConvertInstructions(toBeReturnedType: FieldType, typeOnStack: FieldType): Array[Instruction]
Returns the instructions that return a value of type
typeToBeReturned
, convertingtypeOnStack
to it first if necessary.Returns the instructions that return a value of type
typeToBeReturned
, convertingtypeOnStack
to it first if necessary. IftypeOnStack
isObject
, it will be treated as a generic return type and converted to the required type.- Annotations
- @throws("if `typeOnStack` is not compatible with `toBeReturnedType` and `typeOnStack` is not `Object`")
- final def synchronized[T0](arg0: => T0): T0
- Definition Classes
- AnyRef
- def toString(): String
- Definition Classes
- AnyRef → Any
- def toStringSignature: MethodSignature
- final def wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])
- final def wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])
- final def wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])
Deprecated Value Members
- def finalize(): Unit
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.Throwable]) @Deprecated
- Deprecated