raner
raner

Reputation: 1295

ByteBuddy method implementation that creates a new object

I am using Byte Buddy 1.9.0 as a code generator for an Xtext-based programming language, and I am struggling to produce bytecode for a method that instantiates an "anonymous" class. For all intents and purposes, I'm trying to have Byte Buddy create a method that does the equivalent of this:

package fxxx.test;
class DummyUser
{
  DummyOperator dummy()
  {
    return new DummyUser$1();
  }
}

My compiler has already created the nested "anonymous" class DummyUser$1, but, for the life of me, I cannot come up with the correct Byte Buddy instruction sequence to create a new object of that class and then return that object. After some searching I came across MethodCall.construct(MethodDescription), but my current code only produces the following exception:

java.lang.IllegalStateException: Cannot return void from public fxxx.test.DummyOperator fxxx.test.DummyUser_.dummy()
    at net.bytebuddy.implementation.MethodCall$TerminationHandler$1.resolve(MethodCall.java:2189)
    at net.bytebuddy.implementation.MethodCall.toStackManipulation(MethodCall.java:2405)
    at net.bytebuddy.implementation.MethodCall$Appender.apply(MethodCall.java:2434)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyCode(TypeWriter.java:698)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:683)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod.apply(TypeWriter.java:590)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:5114)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1915)
    at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:197)
    at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:174)
    at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3376)
    at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:3565)
...

This error seems to tell me, somewhat understandably, that since the constructor for the class has an <init>()V signature and technically returns void this is equivalent to returning a void value from a method that should really return some subclass of DummyOperator. I tried to combine the MethodCall.construct with a StackManipulation that duplicates the top of the stack, but as the TypeCreation via the new bytecode is already baked into the MethodCall.construct I don't seem to have access to the newly created raw object instance. The project is not open-sourced yet, but I can provide this snippet (using Xtend syntax) to illustrate what my code is doing:

    val Builder<?> anonymousClass = ... // the anonymous class that has already been created
    val TypeDescription declaringType = describe(anonymousClass) // basically .make.typeDescription
    val MethodDescription constructor = method(declaringType, new TypeDescription.ForLoadedType(void), "<init>", #[]) // new Latent declaringType/returnType
    val MethodCall construct = MethodCall.construct(constructor)
    // ^^^ this value gets return as the new method's Implementation

What am I missing so that the method will properly return the newly created instance?

Upvotes: 1

Views: 804

Answers (1)

raner
raner

Reputation: 1295

So, it looks like I wasn't missing any steps after all, or necessarily doing anything wrong about the object instantiation itself. When I ran this in the debugger, I noticed that the invalid stack manipulation was caused by a type mismatch, which indicated that the return type of method was actually not compatible with the type of the anonymous class (mistake on my part; the language's type system is a little more complex than, let's say, plain Java, and the two types were incompatible in a subtle way). The lesson learned, I guess, is to double-check the type compatibility when encountering exceptions like the above.

Upvotes: 2

Related Questions