如何使用ByteBuddy

时间:2018-02-28 17:02:41

标签: java byte-buddy

我目前正在尝试使用ByteBuddy将java.util.Map键/值对包装为java bean,将地图键公开为普通的getter / setter。

我最初构建构建器如下,允许我将Map作为构造函数参数传递:

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 ) ) );

我不确定如何定义相关的getter / setter方法,以便它们有效地复制此行为:

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

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

我从ByteBuddy那里了解到,我实际上会做类似的事情:

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 */ );

问题是拦截方法调用内部是什么?

1 个答案:

答案 0 :(得分:2)

我最终这样做了

// 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 ) ) );

在这两种情况下,只需要将MethodCall#invoke委托给我尝试使用适当的地图密钥封装的适当Map方法。

同样在set方法的情况下,重要的是将传入的参数0,提供的setter方法的参数委托给使用键的map方法调用。