简体   繁体   English

无法使用 bytebuddy 更改参数值

[英]Failing to change the argument value using bytebuddy

I am trying to add query params to request url using bytebuddy here is my code:我正在尝试使用 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);

and advice is和建议是

@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]);
}

output I am getting is output 我得到的是

!!!!!!!!!!!
http://localhost:8086/movies/5678asdgb?param=myparam
http://localhost:8086/movies/5678

I have tried below advice too but this one is not even capturing the method call.我也尝试过以下建议,但这个建议甚至没有捕获方法调用。

@Advice.OnMethodEnter
public static void before(@Advice.Argument(0) String argument) {
    System.out.println("!!!!!!!!!!!");
    argument = (argument + "asdgb?param=myparam");
    System.out.println(argument);
}

Like you said, in order to change the argument you need readOnly = false .就像你说的,为了改变你需要的论点readOnly = false But like I said, your advice does not cover all three execute() methods.但正如我所说,您的建议并未涵盖所有三种execute()方法。 You would get class cast exceptions for the one taking an URI as a first parameter.对于将URI作为第一个参数的异常,您将获得 class 强制转换异常。 Here is how to fix it:以下是修复方法:

Helper classes to make your sample code compile:使您的示例代码编译的帮助程序类:

public class MyByteBuddy {}
import org.springframework.web.client.RestTemplate;

public class MyRestTemplate extends RestTemplate {}

ByteBuddy advice:字节好友建议:

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);
  }
}

Driver application:司机申请:

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) {}
  }
}

Console log:控制台日志:

https://www.google.com/search?q=scrum
https://www.google.com/search?q=scrum

The problem when using @AllArguments is that you are assigning a value as such使用@AllArguments时的问题是您正在分配一个值

args[0] = (Object) data;

This does not help in terms of Byte Buddy's templating capabilities.这对 Byte Buddy 的模板功能没有帮助。 In effect, this means that you are reading all arguments into an array, assigning data to the first index of that array and then never use it again.实际上,这意味着您正在将所有 arguments 读入一个数组,将data分配给该数组的第一个索引,然后不再使用它。 Instead, you would need to:相反,您需要:

Object[] _args = args;
_args[0] = (Object) data;
args = _args;

While this does not seem to make sense in Java code, it translates into the byte code you want where all arguments are assigned the values of the supplied array.虽然这在 Java 代码中似乎没有意义,但它转换为您想要的字节代码,其中所有 arguments 都分配了提供的数组的值。 It would however be much more efficient to do what kriegaex suggests to use index base proxies for arguments.然而,按照kriegaex建议对 arguments 使用索引基础代理会更有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM