0

Here I required to create a instance of BImpl but BImpl requires to access functionality by an interface A. For this purpose, the class implements this interface A. How Can I wire a delegation of these interface methods of BImpl at runtime ? The idea is that BImpl can use A's methods.

In my case A is known and the AImpl instance is created at run-time.

public static void main(String[] args) {
  B b = (B) Enhancer.create(BImpl.class, new MyInterceptor());
  System.out.println(b.cellValue());
}

interface A {
  String value();
}

class AImpl implements A {

  @Override
  public String value() {
    return "MyA";
  }
}

interface B {
  String cellValue();
}

abstract class BImpl implements B, A {
  @Override
  public String cellValue() {
    return value() + "MyBCell";
  }
}

class MyInterceptor implements MethodInterceptor {

  @Override
  public Object intercept(Object obj, Method method, Object[] args,
                          MethodProxy proxy) throws Throwable {
    System.out.println(method.getName());
    if ("value".equals(method.getName()))
      return method.invoke(obj, args);
    else
      return proxy.invokeSuper(obj, args);
    }
  }
Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
Njax3SmmM2x2a0Zf7Hpd
  • 1,354
  • 4
  • 22
  • 44

1 Answers1

3

What you describe sounds like a mixin pattern. Can you not simply implement a delegation explicitly? Something like:

class BImpl implements B, A {

  private A a;

  public BImpl(A a) {
    this.a = a;
  }

  @Override
  public String cellValue() {
    return value() + "MyBCell";
  }

  @Override
  public String value() {
    return a.value();
  }
}

This should be possible since you say that you know A during compilation.

Otherwise, your approach is probably the correct one for cglib if you are really need to do this at runtime. However, you need to hand a different instance for obj when calling:

return method.invoke(obj, args);

Otherwise you call the intercepted method again and find yourself in an endless loop by hitting MyMethodInterceptor in a loop. You could also safe yourself the branch and use a CallbkackFilter instead.

If you are not bound to cglib, you could also look into my library Byte Buddy which makes this all a little bit more expressive:

new ByteBuddy()
  .subclass(BImpl.class)
  .method(isAnnotatedBy(A.class))
  .intercept(Forwarding.to("a", A.class))
  .make();

The generated class has now a field a which you can set to an instance of any A to which the method invocations of the A interface methods are now delegated. You can set this field by for example using Java reflection. Otherwise, you can use a static field by

Forwarding.to(new A() {
  // A methods
}); 
Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192