Naros
Naros

Reputation: 21113

How to add custom get/set methods using ByteBuddy

I am presently trying to implement wrapping a java.util.Map of key/value pairs using ByteBuddy as a java bean that exposes the map keys as normal getter/setters.

I initially construct the builder as follows allowing me to pass the Map as a constructor argument:

DynamicType.Builder builder = new ByteBuddy()
  .subclass( Object.class )
  .name( customClassName )
  .implement( Serializable.class )
  .defineField( "theMap", Map.class )
  .defineConstructor( Modifier.PUBLIC )
    .withParameters( Map.class )
    .intercept(
      MethodCall.invoke( Object.class.getConstructor() ).onSuper()
        .andThen( FieldAccessor.ofField( "theMap" ).setArgumentAt( 0 ) ) );

What I am not sure about is how to define the associated getter/setter methods so they effectively replicate this behavior:

public Integer getFoo() {
  return theMap.get( "foo" );
}

public void setFoo(Integer foo) {
  theMap.put( "foo", foo );
}

I understand from ByteBuddy that I effectively would do something similar to this:

builder.defineMethod( "getFoo", Integer.class, Modifier.PUBLIC )
  .intercept( /* what goes here */ );

builder.defineMethod( "setFoo", Void.clss, Modifier.PUBLIC )
  .withParameters( Integer.class )
  .intercept( /* what goes here */ );

The question is what goes inside the intercept method call ?

Upvotes: 1

Views: 1030

Answers (1)

Naros
Naros

Reputation: 21113

I ended up doing it this way

// The Getter
builder = builder.defineMethod( "getFoo", Integer.class, Modifier.PUBLIC )
  .intercept(
    MethodCall.invoke( Map.class.getMethod( "get", Object.class ) )
      .onField( "theMap" )
      .with( propertyKey ) );

// The Setter
builder = builder.defineMethod( "setFoo", void.class, Modifier.PUBLIC )
  .withParameters( Integer.class )
  .intercept(
    MethodCall.invoke( Map.class.getMethod( "put", Object.class, Object.class ) )
      .onField( "theMap" )
      .with( propertyKey ) )
      .withArgument( 0 )
      .andThen( new Implementation.Simple( MethodReturn.VOID ) ) );

In both cases, it was simply the need to delegate a MethodCall#invoke to the appropriate Map method I was trying to encapsulate using the appropriate map key.

Also in the case of the set method, it was important to delegate the incoming argument 0, the provided setter method's argument to the map method invocation with the key.

Upvotes: 2

Related Questions