In ByteBuddy, there are seemingly two ways of sequencing Implementation
s.
Using one way, you can chain them together:
// Implementation.Composable; MethodCall "is a" Implementation.Composable; "is a" Implementation
someMethodCall.andThen(someOtherMethodCall)
Using another, you can just add them as a list:
// Implementation.Compound; "is a" Implementation
new Implementation.Compound(myListOfImplementations)
In both cases you end up with a single object that is, itself, an Implementation
, and so is suitable for supplying to the intercept
method.
Are they intended to be essentially equal ways of doing the same thing?
I ask the question because I happen to have several Implementation
s (MethodCall
s as it happens), and so it seemed to me I could just use the Implementation.Compound
constructor that takes a list of Implementation
s. But I'm also familiar with the andThen()
method, so I hesitated.
Anyway, when I use the Implementation.Compound
form, if I add two MethodCall
s to a new Implementation.Compound
and then use the resulting Implementation.Compound
as the argument to an intercept()
call, I get a bytecode verification error at class load time, complaining about a missing stack frame:
java.lang.VerifyError:
Expecting a stack map frame
Exception Details:
Location:
com/foo/GeneratedSubclassOf$com$foo$AbstractFactory$26753A95.frob(Lcom/foo/TestFrob$Thing;Ljava/util/List;)V @15: aload_1
Reason:
Error exists in the bytecode
Bytecode:
0000000: 2b2c 03b9 001e 0200 c000 20b8 0024 b12b
0000010: 2c04 b900 1e02 00c0 0020 b800 27b1
Note the trailing four spaces suggesting to my naïve eyes that perhaps something is missing here. Or perhaps it is some other artifact of my code, but when there is exactly one Implementation
supplied to a new Implementation.Compound
, everything works fine. So I'm thinking that perhaps the Implementation.Compound
construct is not intended for sequencing Implementation
s (but then what is it intended for)? Or maybe there is a bug in Implementation.Compound
(I would think that would be very unlikely)?
When I use the (more cumbersome) Implementation.Composable
construct with the same sub-Implementation
s, everything works fine.
I'm concerned that I am misinterpreting what each construct is supposed to be used for.
An Implementation.Compound
only concatenates two instances without these instances knowing each other. If you compound two implementations that contain:
return doSomething();
You end up with illegal code:
return doSomething();
return doSomething();
Using the andThen
steps of Implementation.Composable
, the first method assures that it does not return a value but clears it's stack. This way, you end up:
doSomething();
return doSomething();
Typically, these two adjusted implementations are then combined by an Implementation.Compound
, but it's important that you inform the first implementation and let it create the compound.