does anyone have an example code for using cglib MulticastDelegate to do something like C# events?

StackOverflow https://stackoverflow.com/questions/4149991

  •  08-10-2019
  •  | 
  •  

Question

Whilst C# has language support for Delegation and Events in Java we have to either use anonymous inner classes for the binding else use reflection code http://oatv.com/pub/a/onjava/2003/05/21/delegates.html. On that pages comments there is a hint about CGLib Multicast Delegates but google codes not seem to know about any example code for that class. Does anyone have a link to a working example else has one at their fingertips?

Was it helpful?

Solution

I know this question is old but maybe somebody is wondering about the same thing one day. For a normal C#-like delegate, you would probably use the MethodDelegate, not the MulticastDelegate. Assume, we have simple Java POJO bean:

public class SimpleBean {
  private String value;
  public String getValue() {
    return value;
  }
  public void setValue(String value) {
    this.value = value;
  }
}

then we can create an instrumented (non-reflective) delegate like this:

public static interface BeanDelegate {
  String getValueFromDelegate();
}

@Test
public void testMethodDelegate() throws Exception {
  SimpleBean bean = new SimpleBean();
  bean.setValue("Hello world!");
  BeanDelegate delegate = (BeanDelegate) MethodDelegate.create(
      bean, "getValue", BeanDelegate.class);
  assertEquals("Hello world!", delegate.getValueFromDelegate());
}

There are some things to note about this example:

  • The factory method MethodDelegate#create takes exactly one method name as its second argument. This is the method the MethodDelegate will proxy for you.

  • There must be a method without arguments defined for the object which is given to the factory method as its first argument. Thus, the MethodDelegate is not as strong as it could be.

  • The third argument must be an interface with exactly one argument. The MethodDelegate implements this interface and can be cast to it. When the method is invoked, it will call the proxied method on the object that is the first argument.

There are some drawbacks/pitfalls:

  • CGlib creates a new class for each proxy. Eventually, this will litter up your permanent generation heap space. (That can cause problems on the long run.)

  • You cannot proxy methods that take arguments. (That sucks.)

  • If your interface takes arguments, the method delegation will simply not work without an exception thrown (the return value will always be null). If your interface requires another return type (even if that is more general), you will get a IllegalArgumentException. (That is weird.)

The MulticastDelegate works a little different. This time we need a bean that actually implements an interface with a single method:

public class SimpleMulticastBean implements DelegatationProvider {
  private String value;
  public String getValue() {
    return value;
  }
  public void setValue(String value) {
    this.value = value;
  }
}

public interface DelegatationProvider {
  void setValue(String value);
}

This time, the interface - called DelegatationProvider in the example - must offer a single method (as before). This interface must be implemented by any object added to this delegation proxy. This can be done as follows:

@Test
public void testMulticastDelegate() throws Exception {
  MulticastDelegate multicastDelegate = MulticastDelegate.create(
      DelegatationProvider.class);
  SimpleMulticastBean first = new SimpleMulticastBean();
  SimpleMulticastBean second = new SimpleMulticastBean();
  multicastDelegate = multicastDelegate.add(first);
  multicastDelegate = multicastDelegate.add(second);

  DelegatationProvider provider = (DelegatationProvider)multicastDelegate;
  provider.setValue("Hello world!");

  assertEquals("Hello world!", first.getValue());
  assertEquals("Hello world!", second.getValue());
}

Again, this implementation has its drawbacks:

  • The objects need to implement a single-method interface. This sucks for third-party libraries and is awkward when you use CGlib to do some magic where this magic gets exposed to the normal code. Also, you could implement your own delegate easily (without byte code though but I doubt that you win so much over manual delegation).

  • When your delegates return a value, you will receive only that of the last delegate you added. All other return values are lost (but retrieved at some point by the multicast delegate).

For further reading: I got inspired and summarized everything I know about cglib in a blog article.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top