2

我正在尝试制作一个 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问题的第一阶段。谢谢

4

1 回答 1

0

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

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

您可以通过调用来实现该接口:

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

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

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

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

于 2016-04-27T10:17:44.370 回答