【问题标题】:ByteBuddy: How to implement field access interceptor?ByteBuddy:如何实现字段访问拦截器?
【发布时间】:2016-04-26 18:18:34
【问题描述】:

我正在尝试制作一个 OGM 来将对象转换为 OrientDB 的顶点。目前我正在使用 GCLib,但我读到 ByteBuddy 可以实现两个关键的东西,如果有效,它将提高 OGM 速度。

  1. ByteBuddy 能否实现字段访问控制?我阅读了文档,但不清楚或不明白。

  2. 动态添加默认的空构造函数。

当前的问题是:我们不知道将作为参数传递的类定义。想法是重新定义类并在没有空构造函数的情况下实现它,添加一个名为 __BB__Dirty 的字段以在检测到分配操作时将对象设置为脏,并强制接口的实现与对象对话。

示例: 一个泛型类:

public class Example {
   int i = 0;
   String stringField;

   public Example(Strinf s) {
       stringField = s;
   }

   public void addToI(){
       i++;
   }
}

现在我们有一个这样的界面:

public interface DirtyCheck {
    public boolean isDirty();
}

所以,我想强制 Example 类实现接口、方法 isDirty()、要处理的字段和默认构造函数,因此应将类转换为:

public class Example implements DirtyCheck {
   int i = 0;
   String stringField;

   boolean __BB__dirty = false;

   public Example() {

   }

   public Example(Strinf s) {
       stringField = s;
   }

   public void addToI(){
       i++;
   }

   public boolean isDirty() {
       return this.__BB__dirty;
   }
}

还有一些神奇的赋值器,因此如果修改了任何字段(__BB__dirty 除外),__BB__dirty 字段将设置为 True;

我已经尝试了第一部分但我失败了:(

...
ByteBuddyAgent.install();

Example ex = new ByteBuddy()
                .redefine(Example.class)
                .defineField("__BB__Dirty", boolean.class, Visibility.PUBLIC)
                .make()
                .load(Example.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent())
                .getLoaded().newInstance();
 ....

 ex.addToI();    // <--- this should set __BB__dirty to true since it
                 //      assign a value to i.

但我得到这个错误:

Exception in thread "main" java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields)
at sun.instrument.InstrumentationImpl.redefineClasses0(Native Method)
at sun.instrument.InstrumentationImpl.redefineClasses(InstrumentationImpl.java:170)
at net.bytebuddy.dynamic.loading.ClassReloadingStrategy$Strategy$1.apply(ClassReloadingStrategy.java:297)
at net.bytebuddy.dynamic.loading.ClassReloadingStrategy.load(ClassReloadingStrategy.java:173)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:4350)
at Test.TestBB.<init>(TestBB.java:33)
at Test.TestBB.main(TestBB.java:23)

我被困在解决 BB 问题的第一阶段。 谢谢

【问题讨论】:

    标签: java byte-buddy


    【解决方案1】:

    Java 虚拟机不支持在重新定义类时更改已加载的类的布局。这不是 Byte Buddy 的限制,而是 VM 实现的限制。

    为了做您想做的事,您应该查看AgentBuilder API,它允许您在加载类之前修改它们。但是,创建代理确实需要您在启动时将其显式添加为代理(与将库添加到类路径相反。

    可以通过调用实现接口:

    .implement(DirtyCheck.class).intercept(FieldAccessor.of("__dirty__");
    

    您还可以通过简单地定义一个默认构造函数来添加:

    .defineConstructor(Visibility.PUBLIC).intercept(SuperMethodCall.INSTANCE)
    

    后一种定义需要超类定义一个默认构造函数。

    【讨论】:

    • 感谢您的回答。 javadoc 有效地说现在不允许添加字段或方法,这个功能将在未来的版本中添加。我想我需要找到另一种方法。我将使用 GCLib 完成 OGM,并在不久的将来返回看看我是否可以在 BB 中以清晰的方式实现它。
    • 不客气。请注意,您可以使用 cglib 也可以使用 Byte Buddy 做任何可能的事情,只有 Byte Buddy 提供更好的运行时性能。
    猜你喜欢
    • 1970-01-01
    • 2020-03-03
    • 2020-02-19
    • 1970-01-01
    • 2019-04-27
    • 1970-01-01
    • 1970-01-01
    • 2011-01-26
    • 1970-01-01
    相关资源
    最近更新 更多