Search code examples
javabyte-buddy

Not able to run ByteBuddy interceptor when @Morph argument is specified


I need to create a custom classes based on some input. What I have atm is this:

    final Class service = ...;
    final Method method = ...;

    final DynamicType.Unloaded unloadedType = new ByteBuddy()
        .subclass(Object.class)
        .name(service.getClass().getSimpleName() + "DynamicResolver")
        .defineMethod(
            endpointName,
            resolveReturnType(method),
            Modifier.PUBLIC)
       .withParameters(parameters)
       .intercept(MethodDelegation
            .withDefaultConfiguration()
            .withBinders(Morph.Binder.install(Morphing.class))
            .to(interceptor).andThen(
                MethodCall.invoke(method).on(service).withArgument(arguments)
            ))
       .make()

What I am doing here is creating a class with a single method that delegates to provided one. However, the created method and delegate method have a bit different parameters. The created method has one argument more (in parameters). The created method does not take that argument, hence the arguments array with argument indexes (one argument less).

So far it's OK. Now, I need to add additional argument when calling delegation method. For the sake of simplicity of the example, imagine we have to add one more string to delegate call.

As I saw from the documentation, the way to manipulate the arguments is using @Morph. So I did:

public interface Morphing<T> {
    T invoke(Object[] args);
}

and my interceptor:

public class Interceptor {
    @RuntimeType
    public Object invoke(
        @Morph final Morphing<Integer> m,
        @AllArguments final Object[] args
    ) {
        System.out.println("!!!");
        return m.invoke(args);
    }
}

Unfortunately, this is not working. When I remove the @Morph argument, the interceptor gets called.

What am I missing here?

EDIT: Is the @Morph used only for subclasses and not when delegating to another instance?

EDIT2: example


Solution

  • Byte Buddy is binding a method of the Object class such that your desired interceptor is no longer triggered. You can add filter(isDeclaredBy(MyInterceptor.class)) after the withDefaultConfiguration() to avoid this. Doing so, you will get an exception that Byte Buddy cannot bind any of your methods.

    The reason that @Morph makes the class ineligable is that there is no super method to be called. In your example, you are defining a new method which does not have an original implementation. You'd need to override an existing method to use the annotation.