无法使用 bytebuddy 更改参数值
Failing to change the argument value using bytebuddy
我正在尝试使用 bytebuddy 添加查询参数以请求 url
这是我的代码:
new AgentBuilder.Default()
.disableClassFormatChanges()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.type(hasSuperType(named("org.springframework.web.client.RestTemplate")))
.transform(new Transformer.ForAdvice().include(MyByteBuddy.class.getClassLoader())
.advice(ElementMatchers.named("execute"), "agent.RestTemplateAdvice"))
.installOn(instrumentation);
建议是
@Advice.OnMethodEnter
public static void before(@Advice.AllArguments Object[] args) {
System.out.println("!!!!!!!!!!!");
String data = args[0].toString();
data = (data + "asdgb?param=myparam");
System.out.println(data);
args[0] = (Object)data;
System.out.println(args[0]);
}
我得到的输出是
!!!!!!!!!!!
http://localhost:8086/movies/5678asdgb?param=myparam
http://localhost:8086/movies/5678
我也试过下面的建议,但是这个甚至没有捕获方法调用。
@Advice.OnMethodEnter
public static void before(@Advice.Argument(0) String argument) {
System.out.println("!!!!!!!!!!!");
argument = (argument + "asdgb?param=myparam");
System.out.println(argument);
}
就像你说的,为了改变你需要的论点readOnly = false
。但正如我所说,您的建议并未涵盖所有三种 execute()
方法。对于将 URI
作为第一个参数的那个,你会得到 class 强制转换异常。修复方法如下:
Helper classes 使您的示例代码编译:
public class MyByteBuddy {}
import org.springframework.web.client.RestTemplate;
public class MyRestTemplate extends RestTemplate {}
ByteBuddy 建议:
import net.bytebuddy.asm.Advice;
import java.net.URI;
import java.net.URISyntaxException;
import static net.bytebuddy.implementation.bytecode.assign.Assigner.Typing.DYNAMIC;
public class RestTemplateAdvice {
@Advice.OnMethodEnter()
public static void before(
@Advice.Argument(value = 0, typing = DYNAMIC, readOnly = false) Object url
)
throws URISyntaxException
{
String newURL = url.toString() + "search?q=scrum";
url = url instanceof URI ? new URI(newURL) : newURL;
System.out.println(url);
}
}
驱动申请:
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import org.springframework.web.client.HttpClientErrorException;
import java.lang.instrument.Instrumentation;
import java.net.URI;
import java.net.URISyntaxException;
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.springframework.http.HttpMethod.GET;
class BBChangeRestTemplateReturnValue_64257928 {
public static void main(String[] args) throws URISyntaxException {
applyAdvice();
performSampleRequests();
}
private static void applyAdvice() {
Instrumentation instrumentation = ByteBuddyAgent.install();
new AgentBuilder.Default()
.disableClassFormatChanges()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.type(hasSuperType(named("org.springframework.web.client.RestTemplate")))
.transform(
new AgentBuilder.Transformer.ForAdvice()
.include(MyByteBuddy.class.getClassLoader())
.advice(named("execute"), "RestTemplateAdvice")
)
.installOn(instrumentation);
}
private static void performSampleRequests() throws URISyntaxException {
try {
new MyRestTemplate().execute("https://www.google.com/", GET, null, null);
}
catch (HttpClientErrorException ignored) {}
try {
new MyRestTemplate().execute(new URI("https://www.google.com/"), GET, null, null);
}
catch (HttpClientErrorException ignored) {}
}
}
控制台日志:
https://www.google.com/search?q=scrum
https://www.google.com/search?q=scrum
使用 @AllArguments
时的问题是您正在分配一个值
args[0] = (Object) data;
这对 Byte Buddy 的模板功能没有帮助。实际上,这意味着您正在将所有参数读入一个数组,将 data
分配给该数组的第一个索引,然后不再使用它。相反,您需要:
Object[] _args = args;
_args[0] = (Object) data;
args = _args;
虽然这在 Java 代码中似乎没有意义,但它会转换为您想要的字节代码,其中所有参数都被分配了所提供数组的值。然而,kriegaex 建议使用索引基代理作为参数会更有效率。
我正在尝试使用 bytebuddy 添加查询参数以请求 url 这是我的代码:
new AgentBuilder.Default()
.disableClassFormatChanges()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.type(hasSuperType(named("org.springframework.web.client.RestTemplate")))
.transform(new Transformer.ForAdvice().include(MyByteBuddy.class.getClassLoader())
.advice(ElementMatchers.named("execute"), "agent.RestTemplateAdvice"))
.installOn(instrumentation);
建议是
@Advice.OnMethodEnter
public static void before(@Advice.AllArguments Object[] args) {
System.out.println("!!!!!!!!!!!");
String data = args[0].toString();
data = (data + "asdgb?param=myparam");
System.out.println(data);
args[0] = (Object)data;
System.out.println(args[0]);
}
我得到的输出是
!!!!!!!!!!!
http://localhost:8086/movies/5678asdgb?param=myparam
http://localhost:8086/movies/5678
我也试过下面的建议,但是这个甚至没有捕获方法调用。
@Advice.OnMethodEnter
public static void before(@Advice.Argument(0) String argument) {
System.out.println("!!!!!!!!!!!");
argument = (argument + "asdgb?param=myparam");
System.out.println(argument);
}
就像你说的,为了改变你需要的论点readOnly = false
。但正如我所说,您的建议并未涵盖所有三种 execute()
方法。对于将 URI
作为第一个参数的那个,你会得到 class 强制转换异常。修复方法如下:
Helper classes 使您的示例代码编译:
public class MyByteBuddy {}
import org.springframework.web.client.RestTemplate;
public class MyRestTemplate extends RestTemplate {}
ByteBuddy 建议:
import net.bytebuddy.asm.Advice;
import java.net.URI;
import java.net.URISyntaxException;
import static net.bytebuddy.implementation.bytecode.assign.Assigner.Typing.DYNAMIC;
public class RestTemplateAdvice {
@Advice.OnMethodEnter()
public static void before(
@Advice.Argument(value = 0, typing = DYNAMIC, readOnly = false) Object url
)
throws URISyntaxException
{
String newURL = url.toString() + "search?q=scrum";
url = url instanceof URI ? new URI(newURL) : newURL;
System.out.println(url);
}
}
驱动申请:
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import org.springframework.web.client.HttpClientErrorException;
import java.lang.instrument.Instrumentation;
import java.net.URI;
import java.net.URISyntaxException;
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.springframework.http.HttpMethod.GET;
class BBChangeRestTemplateReturnValue_64257928 {
public static void main(String[] args) throws URISyntaxException {
applyAdvice();
performSampleRequests();
}
private static void applyAdvice() {
Instrumentation instrumentation = ByteBuddyAgent.install();
new AgentBuilder.Default()
.disableClassFormatChanges()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.type(hasSuperType(named("org.springframework.web.client.RestTemplate")))
.transform(
new AgentBuilder.Transformer.ForAdvice()
.include(MyByteBuddy.class.getClassLoader())
.advice(named("execute"), "RestTemplateAdvice")
)
.installOn(instrumentation);
}
private static void performSampleRequests() throws URISyntaxException {
try {
new MyRestTemplate().execute("https://www.google.com/", GET, null, null);
}
catch (HttpClientErrorException ignored) {}
try {
new MyRestTemplate().execute(new URI("https://www.google.com/"), GET, null, null);
}
catch (HttpClientErrorException ignored) {}
}
}
控制台日志:
https://www.google.com/search?q=scrum
https://www.google.com/search?q=scrum
使用 @AllArguments
时的问题是您正在分配一个值
args[0] = (Object) data;
这对 Byte Buddy 的模板功能没有帮助。实际上,这意味着您正在将所有参数读入一个数组,将 data
分配给该数组的第一个索引,然后不再使用它。相反,您需要:
Object[] _args = args;
_args[0] = (Object) data;
args = _args;
虽然这在 Java 代码中似乎没有意义,但它会转换为您想要的字节代码,其中所有参数都被分配了所提供数组的值。然而,kriegaex 建议使用索引基代理作为参数会更有效率。