General Interceptor for Getters and Setters on an Interface

960 views
Skip to first unread message

Dave Bixler

unread,
Nov 4, 2015, 8:24:59 AM11/4/15
to Byte Buddy
I'm new to ByteBuddy and am trying to dive into understanding the library.  It's a little tough, but I think I'm getting there.  I'm trying to create a dynamic class that can intercept all getters and setters based on an interface and store the property names into a Set.  I'm really struggling because I can't seem to get the method interceptor to work (probably just because of a lack of understanding).  I've searched all over but unable to find enough information.  Here's my example:

I have an interface that I want the dynamic class to implement defined as:
public interface SomePojo {
 
public String getName ();
 
public void setName (String name);
 
 
public String getFoo ();
 
public void setFoo (String foo);
}


I then defined a "SetterGetterInterceptor" as:
class SetterGetterInterceptor {
 
private Map<String,Object> container = new HashMap<String, Object> ();
 
 
public SetterGetterInterceptor () {
 
}
 
 
public Map<String, Object> getContainer () {
 
return this.container;
 
}
 
 
@RuntimeType
 
public Object intercept(@AllArguments Object[] allArguments,@Origin Method method) {

 
String methodName = method.getName ();
 
 
//
 
// We're only interested in getters and setters.  If it's neither of these,
 
// we're just going to return null, but we should probably throw some
 
// exception like NoSuchMethod.
 
//
 
if (methodName.startsWith("get")) {
 
String property = methodName.substring (3);
 
return this.container.get(property);
 
} else if (methodName.startsWith("set")) {
 
String property = methodName.substring (3);
 
this.container.put(property, allArguments[0]);
 
}


 
return null;
 
}
}


And my main is defined as:


public class BBTest {
 
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
 
SomePojo sp = new ByteBuddy ()
 
.subclass(SomePojo.class)
// .method(ElementMatchers.any()).intercept(new SetterGetterInterceptor ())
 
.make ()
 
.load(BBTest.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
 
.getLoaded()
 
.newInstance();
 
 sp
.setFoo("foo");
 
 
System.out.println (sp.getFoo());
 
}
}


I just cannot figure out how to get the dynamic class to intercept the getters and setters correctly.  Any help would be appreciated, and thank you in advance.  I commented out the .method() call because it was throwing an exception.

Dave Bixler

unread,
Nov 4, 2015, 8:30:26 AM11/4/15
to Byte Buddy
I'm going to answer my own question (I think).  I changed the main() to be:

 public static void main(String[] args) throws InstantiationException, IllegalAccessException {
 
SomePojo sp = new ByteBuddy ()
 
.subclass(SomePojo.class)

 
.method(ElementMatchers.any()).intercept(MethodDelegation.to(new SetterGetterInterceptor ()))
 
.make ()
 
.load(BBTest.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)

 
.getLoaded()
 
.newInstance();
 
 sp
.setFoo("foo");
 
 
System.out.println (sp.getFoo());
 
}

And it worked!  Was this the correct way of doing the delegation?

Rafael Winterhalter

unread,
Nov 4, 2015, 7:04:25 PM11/4/15
to Dave Bixler, Byte Buddy
Hi,
I assume that before, your interceptor was package-private and could not be seen by any class that is loaded by another class loader. Therefore, you might have observed an exception.

Some tips on your interception: You do not want to intercept "any" method. you want to intercept getters and setters. This can be expressed by "isGetter().or(isSetter())". In this case, classes like "toString" are not intercepted which would return null for your above example.

Also, your interceptor could be more efficient by offering two methods. Byte Buddy would figure out the best method for you. For example:

public class GetterSetterInterceptor {
 
  private final Map<String, Object> values = new HashMap<>();

  @RuntimeType
  public Object interceptGetter(@Origin Method m) {
    // handle getter
  }

  public void interceptSetter(@Origin Method m, Object argument) {
    // handle setter with single argument
  }
}

Byte Buddy will intercept the setter with the setter method and the getter with the getter method by default as both interceptions are considered the "best match".
Best of luck with using Byte Buddy and thanks for following up on your own question.
Cheers, Rafael

--
You received this message because you are subscribed to the Google Groups "Byte Buddy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to byte-buddy+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages