How can I bind constructor parameter to a instance field?

byte-buddy, java

Solution

Unfortunately, there is no good way in the moment. I did however take this as an inspiration to refactor the `FieldAccessor` implementation which now allows you to do the following:

builder.defineField("desiredField", 
          DispatcherInvocationHandler.class, 
          Visibility.PRIVATE, FieldManifestation.FINAL)
       .defineConstructor(Visibility.PUBLIC)
       .withParameters(String.class)
       .intercept(MethodCall.invokeSuper() // Given such a constructor exists
         .andThen(FieldAccessor.ofField("desiredField").setsArgumentAt(0)))
       .make()
       .load(BytebuddyProxyGenerator.class.getClassLoader())
       .getLoaded();

When you define such an explicit setter, the instrumentation also becomes chainable by itself. You can therefore set multiple fields such as:

FieldAccessor.ofField("foo")
             .setsArgumentAt(0)
             .andThen(FieldAccessor.ofField("bar").setsArgumentAt(1));

With the above implementation, a constructor (or any method) would be implemented similar to:

class Sample {
  Object foo, bar;
  Sample(Object a1, Object a2) {
    foo = a1;
    bar = a2;
  }
}

This additional API is released with Byte Buddy 1.5.2.

Problem

Is it possible create new final field on a class and create a constructor with parameter that is set to that final field on class instantiation? I tried several approaches and searched for answers but found no example how to do it. What I have now: ``` Class proxyClass = new ByteBuddy().subclass(Object.class).implement((Type[]) interfaces) .defineField("dispatcherInvocationHandler", ByteBuddyDispatcherInvocationHandler.class, Modifier.PRIVATE + Modifier.FINAL) .defineConstructor(Modifier.PUBLIC) .withParameter(ByteBuddyDispatcherInvocationHandler.class) .intercept(MethodCall.invokeSuper().andThen(/* copy argument to field */)) .method(ElementMatchers.any()) .intercept(InvocationHandlerAdapter.toField("dispatcherInvocationHandler")) .make() .load(BytebuddyProxyGenerator.class.getClassLoader()) .getLoaded(); ``` I don't want to make field public and I don't want to create property with setter / getter to that field. I'd like to end up with something like: ``` public class DontCare { private final ByteBuddyDispatcherInvocationHandler dispatcherInvocationHandler; public DontCare(ByteBuddyDispatcherInvocationHandler arg) { super(); this.dispatcherInvocationHandler = arg; } } ``` Is there any simple way how to do this? Updated 31.10.2016 Finally I got it working with the help of Rafael and 1.5.2 version of the ByteBuddy library. Working code is this: ``` Class proxyClass = new ByteBuddy().subclass(Object.class).implement((Type[]) interfaces) .defineField("dispatcherInvocationHandler", ByteBuddyDispatcherInvocationHandler.class, Modifier.PRIVATE + Modifier.FINAL) .defineConstructor(Modifier.PUBLIC) .withParameter(ByteBuddyDispatcherInvocationHandler.class) .intercept( MethodCall.invoke(Object.class.getConstructor()) .onSuper() .andThen( FieldAccessor.ofField("dispatcherInvocationHandler") .setsArgumentAt(0) ) ) .method(ElementMatchers.any()) .intercept(InvocationHandlerAdapter.toField("dispatcherInvocationHandler")) .make() .load(ByteBuddyProxyGenerator.class.getClassLoader()) .getLoaded(); ```

Original source