用于将新创建的对象传递给方法的 Byte Buddy 代码
Byte Buddy code for passing a newly created object to a method
因此,我正在尝试使用 Byte Buddy 生成一些相对简单的代码,但我将 运行 保留为异常。
基本上,我正在尝试让 Byte Buddy(版本 1.9.0)生成以下等价物 Java class(这只是一个简化的示例;问题通常发生在试图将新创建的对象传递给方法):
public class CalendarSetter
{
public void setCalendarTime(Calendar calendar)
{
calendar.setTime(new Date());
}
}
我想出的字节好友代码如下(使用Xtend语法,但它非常接近Java):
val Builder<?> builder = new ByteBuddy()
.subclass(Object).name("CalendarSetter").merge(Visibility.PUBLIC)
.defineMethod("setCalendarTime", void, Visibility.PUBLIC)
.withParameter(Calendar)
.intercept(MethodCall.invoke(new ForLoadedMethod(Calendar.getDeclaredMethod("setTime", Date)))
.onArgument(0)
.withMethodCall(MethodCall.construct(Date.getConstructor)))
builder.make.load(class.classLoader).loaded
不幸的是,这只会产生以下异常:
java.lang.IllegalStateException: Cannot assign public java.util.Date() to java.util.Date arg0
at net.bytebuddy.implementation.MethodCall$ArgumentLoader$ForMethodCall.resolve(MethodCall.java:1470)
at net.bytebuddy.implementation.MethodCall.toStackManipulation(MethodCall.java:2397)
at net.bytebuddy.implementation.MethodCall$Appender.apply(MethodCall.java:2434)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyCode(TypeWriter.java:698)
...
调试器中的一些进一步探索表明这是由于 Date
的构造函数(像所有构造函数一样)具有 return 类型的 void
,反过来,与 java.util.Date
不兼容。 Byte Buddy 的 VoidAwareAssigner
产生非法的 StackManipulation
因为源类型是 void
而目标类型是非 void
并且 Typing
不是动态的。
我希望 VoidAwareAssigner
确实应该知道构造函数本质上是 void
方法,但我可能在这里遗漏了其他东西。
在 Byte Buddy 中将新创建的对象作为方法参数传递的正确方法是什么?
更新: 我能够通过添加 .withAssigner(custom, Typing.DYNAMIC)
和一个总是 "trivial" Assigner
的自定义 return 来避免异常] 是 StackManipulation.Trivial
。此变通方法生成看似正确(且有效)的字节码:
public class CalendarSetter {
public void setCalendarTime(java.util.Calendar);
Code:
0: aload_1
1: new #8 // class java/util/Date
4: dup
5: invokespecial #12 // Method java/util/Date."<init>":()V
8: invokevirtual #18 // Method java/util/Calendar.setTime:(Ljava/util/Date;)V
11: return
...
但是我仍然觉得这不是真正正确的方法,并且可能过度简化了一些我不知道的场景...
你发现了我刚刚在 master 分支上修复的错误。它将成为 1.10.12 版本的一部分。
字节好友错误地将构造函数的 return 类型解析为 void。
因此,我正在尝试使用 Byte Buddy 生成一些相对简单的代码,但我将 运行 保留为异常。
基本上,我正在尝试让 Byte Buddy(版本 1.9.0)生成以下等价物 Java class(这只是一个简化的示例;问题通常发生在试图将新创建的对象传递给方法):
public class CalendarSetter
{
public void setCalendarTime(Calendar calendar)
{
calendar.setTime(new Date());
}
}
我想出的字节好友代码如下(使用Xtend语法,但它非常接近Java):
val Builder<?> builder = new ByteBuddy()
.subclass(Object).name("CalendarSetter").merge(Visibility.PUBLIC)
.defineMethod("setCalendarTime", void, Visibility.PUBLIC)
.withParameter(Calendar)
.intercept(MethodCall.invoke(new ForLoadedMethod(Calendar.getDeclaredMethod("setTime", Date)))
.onArgument(0)
.withMethodCall(MethodCall.construct(Date.getConstructor)))
builder.make.load(class.classLoader).loaded
不幸的是,这只会产生以下异常:
java.lang.IllegalStateException: Cannot assign public java.util.Date() to java.util.Date arg0
at net.bytebuddy.implementation.MethodCall$ArgumentLoader$ForMethodCall.resolve(MethodCall.java:1470)
at net.bytebuddy.implementation.MethodCall.toStackManipulation(MethodCall.java:2397)
at net.bytebuddy.implementation.MethodCall$Appender.apply(MethodCall.java:2434)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyCode(TypeWriter.java:698)
...
调试器中的一些进一步探索表明这是由于 Date
的构造函数(像所有构造函数一样)具有 return 类型的 void
,反过来,与 java.util.Date
不兼容。 Byte Buddy 的 VoidAwareAssigner
产生非法的 StackManipulation
因为源类型是 void
而目标类型是非 void
并且 Typing
不是动态的。
我希望 VoidAwareAssigner
确实应该知道构造函数本质上是 void
方法,但我可能在这里遗漏了其他东西。
在 Byte Buddy 中将新创建的对象作为方法参数传递的正确方法是什么?
更新: 我能够通过添加 .withAssigner(custom, Typing.DYNAMIC)
和一个总是 "trivial" Assigner
的自定义 return 来避免异常] 是 StackManipulation.Trivial
。此变通方法生成看似正确(且有效)的字节码:
public class CalendarSetter {
public void setCalendarTime(java.util.Calendar);
Code:
0: aload_1
1: new #8 // class java/util/Date
4: dup
5: invokespecial #12 // Method java/util/Date."<init>":()V
8: invokevirtual #18 // Method java/util/Calendar.setTime:(Ljava/util/Date;)V
11: return
...
但是我仍然觉得这不是真正正确的方法,并且可能过度简化了一些我不知道的场景...
你发现了我刚刚在 master 分支上修复的错误。它将成为 1.10.12 版本的一部分。
字节好友错误地将构造函数的 return 类型解析为 void。