GithubHelp home page GithubHelp logo

Comments (4)

raphw avatar raphw commented on August 19, 2024

A lambda expression simply binds a value that is returned from a bootstrap method. If you want to bind a value, you should either intercept the constructor (members) or the initializer (static). From there, construct an expression and bind the result to the field. You could also use MethodDelegation or Advice to implement this code.

from byte-buddy.

LarsBodewig avatar LarsBodewig commented on August 19, 2024

Thanks for taking the time!

As far as I understand I do intercept the initializer and create an expression by using FieldAccessor.ofField("_writeObject").setsValue(). If I change my added field to type String and use setsValue("myString") the field will be correctly initialized.
I only struggle to represent the method reference as the value.

I am not sure if MethodDelegation could help, as I don't try to invoke ObjectOutputStream#defaultWriteObject during initialization but assign the method reference instead. The docs also state

For invoking a method on another instance, use the MethodCall implementation

so I tried to assign a MethodCall as value

// in MyPlugin.apply
builder = builder
        .invokable(net.bytebuddy.matcher.ElementMatchers.isTypeInitializer())
        .intercept(
            net.bytebuddy.implementation.FieldAccessor.ofField("_writeObject").setsValue(
                net.bytebuddy.implementation.MethodCall.of(
                    new net.bytebuddy.description.method.MethodDescription.ForLoadedMethod(
                        java.io.ObjectOutputStream.class.getMethod("defaultWriteObject"))
                .withArgument(0)));

but it fails with the same exception as before.

from byte-buddy.

raphw avatar raphw commented on August 19, 2024

You will have to use InvokeDynamic#lambda to bind a lambda expression (or method reference). Unfortunately, there is not yet a way to set the lambda expression as a field.

Instead, you can construct the lambda expression manually using MethodInvocation by defining a manual call to LambdaMetaFactory.

When using MethodCall, you would also need to use the setsField method from there.

from byte-buddy.

LarsBodewig avatar LarsBodewig commented on August 19, 2024

For future reference, if anyone has the same issue:

I tried to manually call the LambdaMetaFactory which should in theory return a MethodHandle that can be written to the byte code as a constant but ultimately got stuck on constructing the lambda correctly.

builder = builder.invokable(isTypeInitializer()).intercept(
                            FieldAccessor.ofField("_writeObject")
                                    .setsValue(
                                            // does not work :(
                                            LambdaMetafactory.metafactory(
                                                    MethodHandles.lookup(),
                                                    "apply",
                                                    MethodType.methodType(WriteInterface.class, ObjectOutputStream.class),
                                                    MethodType.methodType(void.class, ObjectOutputStream.class),
                                                    MethodHandles.lookup().findVirtual(ObjectOutputStream.class, "defaultWriteObject", MethodType.methodType(void.class)),
                                                    MethodType.methodType(void.class)
                                            ).getTarget()));

I ended up creating another dynamic type to implement the functional interface and delegate the call to the target method (the "pre-java-8-way"). Then I call its default constructor to set my static field. This does not solve the original question/error but is sufficient in my use case.

// in MyPlugin.apply
DynamicType writeInterface = new net.bytebuddy.ByteBuddy()
                    .makeInterface()
                    .name("WriteInterface")
                    .defineMethod("apply", void.class, Visibility.PUBLIC)
                    .withParameter(ObjectOutputStream.class, "out")
                    .throwing(IOException.class)
                    .withoutCode()
                    .make();

DynamicType writeDefaultImpl = new ByteBuddy()
                    .subclass(Object.class)
                    .name("DefaultImpl")
                    .implement(writeInterface.getTypeDescription())
                    .defineMethod("apply", void.class, Visibility.PUBLIC)
                    .withParameter(ObjectOutputStream.class, "out")
                    .throwing(IOException.class)
                    .intercept(MethodCall.invoke(new MethodDescription.ForLoadedMethod(
                            ObjectOutputStream.class.getMethod("defaultWriteObject"))).onArgument(0))
                    .make();

builder = builder.require(writeInterface);
builder = builder.require(writeDefaultImpl);

builder = builder.defineField(
          "_writeObject", 
          writeInterface.getTypeDescription(),
          Visiblity.PUBLIC, 
          Ownership.STATIC);

builder = builder.invokable(isTypeInitializer()).intercept(
                    MethodCall.construct(writeDefaultImpl.getTypeDescription().getDeclaredMethods().filter(isDefaultConstructor()).getOnly())
                           .setsField(named("_writeObject")));

from byte-buddy.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.