Class | Description |
---|---|
AnnotationReader |
Reads annotation inner data.
|
InvokeClassBuilder |
Invocation replacer class adapter.
|
InvokeReplacerMethodAdapter |
Invocation replacer method adapter.
|
MethodSignatureVisitor |
Resolves method signature and holds all information.
|
ProxettaAsmUtil |
Various ASM utilities used by
Proxetta . |
ProxettaClassBuilder |
Proxetta class builder.
|
ProxettaCtorBuilder |
Destination ctor builder
|
ProxettaMethodBuilder | |
ProxettaWrapperClassBuilder | |
TargetClassInfoReader |
Reads info from target class.
|
TypeInfoImpl |
Implementation of
TypeInfo . |
WorkData |
Holds various information about the current process of making proxy.
|
This package assembles proxy classes. You will probably like to keep out from this code:)
During creation of proxy methods, several replacement and modification happens in order to produce valid proxy subclass. Here is the list of all such rules.
Proxy subclass must contain all constructors as target subclass. New constructors simply delegates invocation to the super class. All constructor annotations are copied.
Last method in proxy chain is the one that simply delegates the invocation to the target method in super class.
Proxy subclass must contain all type annotations as the target one.
Proxy methods must contain all type annotations as the target one.
Offset of all local variables has to be incremented by the size of target method argument list.
Size of arguments list is the number of 32bit words used by arguments on stack, which means that
all types has length of 1 word, except Long
and Double
that weight 2 words
(or one dword).
iconst_1 istore_1
iconst_1 istore_13
Here is the order of local variables:
Therefore, index 0 is left as it is and offset will not be added to it.
Call to ProxyTarget.argsCount()
has to be replaces with hardcoded arguments count.
Method call is simply replaces with appropriate load instruction: iload_n
where n is in [0. 5];
bipush n
where n is in byte range; or sipush n
when n is in integer range.
Call to ProxyTarget.getArgType(int )
has to be replaces with hardcoded argument Class, where argument
index is provided as an argument for ProxyTarget.getArgType(int )
.
Method call is replaced with getClass()
call on specified argument. If argument is an primitive
then method is replaced with reading the TYPE
attribute of appropriate wrapper.
One caveat: opcode for pushing argument offset to stack is not removed from the bytecode, due to performance issues of class creation. Instead, this value is poped from the stack before method call is replaced. It is assumed that this value is an integer.
iconst_1 invokestatic package/ProxyTarget.getArgClass astore_1 iconst_2 invokestatic package/ProxyTarget.getArgClass astore_2
(iconst_1 pop) aload_1 invokevirtual java/lang/Object.getClass astore 13 (iconst_2 pop) getstatic java/lang/Byte.TYPE astore 14
Call to ProxyTarget.getArg(int )
has to be replaces with hardcoded argument value, where
index is provided as an argument for ProxyTarget.getArg(int )
.
If argument is a primitive, its wrapper object will be created.
iconst_1 invokestatic package/ProxyTarget.getArg astore_1 bipush 6 invokestatic package/ProxyTarget.getArg astore_3
aload_1 astore_13 lload 6 invokestatic java/lang/Long.<init> astore 14
Call to ProxyTarget.setArg(Object, int )
has to be replaces with hardcoded setting of the argument value,
where index is provided as an argument for ProxyTarget.setArg(Object, int )
.
If argument is a primitive, its wrapper object must be provided.
Call to ProxyTarget.createArgsArray()
has to be replaces with hardcoded creation of an object array,
where elements are target method arguments. Primitive arguments are wrapped.
Call to ProxyTarget.invokeAndGetResult()
has to be replaced with call to super target method. Since target methods
may have one or more arguments, it is required to push all arguments to the stack prior to call of super target method.
Note that aload_0
is always the first instruction (load this
), no matter how many arguments there are.
invokestatic package/ProxyTarget.invoke
aload_0 aload_1 iload_2 ... invokespecial package/Target.method
Situation here is a bit more complicated since return value must be provided, so the following fixes has to be applied, too.
When ProxyTarget.invoke()
is invoked without assignment, POP/POP2
instruction
is added afterwards, to remove the value from the stack. For targets that do not return void, this opcode
has to be fixed, i.e. removed. (Fact is that targets that return void, do not have POP:).
When ProxyTarget.invoke()
is invoked with assignment, xSTORE
instruction
is added afterwards, to assign return value to a local variable. Therefore, it has to be loaded again on stack
before return.
Creates all return values, performs casting for small types.
Returns the target class.
Returns target method name.
Returns return type of the target method or null
if metod returns void.
Access to advice's fields has to be replaced with access to local fields. In relation with [A5].
All fields from advice has to be copied to proxy, with proxy index added to the name, to prevent duplicate names.
Static block of an advice should be copied to the proxy, with fixed field access (see F5).
Advice's constructor will be copied to regular methods, except first two instructions (calling super constructor) will be ignored. Field access will be fixed (see F5).
Copyright © 2003-present Jodd Team