英文:
calling lambda from an intercept method with bytebuddy raises java.lang.NoClassDefFoundError:
问题
以下是您要翻译的内容:
我正在尝试使用ByteBuddy和Java代理进行一些仪器化工作。在其中的一个步骤中,我想捕获堆栈跟踪并使用我关心的调用进行过滤。让我们想象一个premain函数如下所示:
public class SeleniumReporter {
public static void premain(final String agentArgs, final Instrumentation inst) {
new AgentBuilder.Default()
.with(new AgentBuilder.InitializationStrategy.SelfInjection.Eager())
.type(named("org.openqa.selenium.remote.RemoteWebDriver"))
.transform((builder, type, classLoader, module) -> builder
.method(nameStartsWith("findElement")
.and(takesArguments(By.class).or(takesArguments(String.class, String.class)))
.and(isPublic())
)
.intercept(Advice.to(FindElementInterceptor.class))
)
.installOn(inst);
}
}
拦截器的形式如下:
public class FindElementInterceptor {
@Advice.OnMethodExit
public static void log(@Advice.This RemoteWebDriver driver, @Advice.Origin String method, @Advice.AllArguments Object[] args) {
/*
... 一些额外的代码
*/
final String stackTrace = Arrays.stream(Thread.currentThread().getStackTrace())
.map(t -> String.format("%s:%s", t.getClassName(), t.getMethodName()))
.filter(s -> !s.startsWith("org.codehaus.plexus."))
.filter(s -> !s.startsWith("org.apache.maven."))
.collect(Collectors.joining(";"));
System.out.println(stackTrace);
}
}
运行该代码会抛出java.lang.NoClassDefFoundError,因为Lambda表达式没有被加载。因此,我的问题是:我该如何确保它们被加载?我考虑过创建一个包含所有实用程序的类,并通过ByteBuddy加载它。是否有更加优雅的方法?
英文:
I am trying to do some instrumentation using ByteBuddy and a java agent. In one of the steps, I would like to capture the stacktrace and filter it with the calls that I care about. Let's imagine a premain function looks like this:
public class SeleniumReporter {
public static void premain(final String agentArgs, final Instrumentation inst) {
new AgentBuilder.Default()
.with(new AgentBuilder.InitializationStrategy.SelfInjection.Eager())
.type(named("org.openqa.selenium.remote.RemoteWebDriver"))
.transform((builder, type, classLoader, module) -> builder
.method(nameStartsWith("findElement")
.and(takesArguments(By.class).or(takesArguments(String.class, String.class)))
.and(isPublic())
)
.intercept(Advice.to(FindElementInterceptor.class))
)
.installOn(inst);
}
}
and an interceptor takes this form:
public class FindElementInterceptor {
@Advice.OnMethodExit
public static void log(@Advice.This RemoteWebDriver driver, @Advice.Origin String method, @Advice.AllArguments Object[] args) {
/*
... Some extra code
*/
final String stackTrace = Arrays.stream(Thread.currentThread().getStackTrace())
.map(t -> String.format("%s:%s", t.getClassName(), t.getMethodName()))
.filter(s -> !s.startsWith("org.codehaus.plexus."))
.filter(s -> !s.startsWith("org.apache.maven."))
.collect(Collectors.joining(";"));
System.out.println(stackTrace);
}
}
Running that code will throw a java.lang.NoClassDefFoundError because the lambda expression are not loaded. Hence, my question is: What can I do to ensure there are loaded? I was thinking of creating a class and load it through ByteBuddy with all the utils. Is there a more elegant way?
答案1
得分: 1
Byte Buddy无法将lambda表达式从advice方法复制到目标方法。从技术上讲,Lambda只是在定义它的类中的私有方法,这些方法对于目标类是不可用的。
改为使用常规迭代来避免这个问题。或者,您需要在单独的类中实现这些表达式,并使用ClassInjector
将这些类注入到目标类加载器中。
英文:
Byte Buddy cannot copy the lambda expressions from the advice method to the target method. Lambdas are technically speaking only private methods in the class that defines it which will not be available to the target class.
Use regular iteration instead to avoid this problem. Alternatively, you need to implement the expressions in individual classes and inject these classes into the target class loader using a ClassInjector
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论