ByteBuddy MemberSubstitution | Невозможно заменить доступ к полю методом - PullRequest
0 голосов
/ 26 мая 2020

У меня есть вариант использования, когда я хочу заменить чтение и запись поля вызовом метода. У меня есть следующий код агента для достижения того же:

public static void premain(String arguments, Instrumentation instrumentation) throws Exception {
            new AgentBuilder.Default()
                    .type(isAnnotatedWith(Cache.class))
                    .transform(new AgentBuilder.Transformer() {
                        @Override
                        public DynamicType.Builder transform(DynamicType.Builder builder,
                                                             TypeDescription typeDescription,
                                                             ClassLoader classloader,
                                                             JavaModule module) {

                            try {

                                builder = builder.visit(MemberSubstitution.strict()
                                        .field(named("sourceIds")).onRead()
                                        .replaceWith(ReferenceDataService.class.getDeclaredMethod("getReplaceSourceIds"))
                                        .on(any()));
                            } catch (NoSuchMethodException e) {
                                System.out.println("Exception occured");
                            }


                            try {
                                builder = builder.visit(MemberSubstitution.strict()
                                        .field(named("cnt")).onWrite()
                                        .replaceWith(ReferenceDataService.class.getDeclaredMethod("setter",int.class))
                                        .on(any()));
                            } catch (NoSuchMethodException e) {
                                e.printStackTrace();
                            }

                            return builder;
                        }
                    }).installOn(instrumentation);
    }

Как вы можете видеть выше, я заменяю любой доступ для чтения sourceIds на getReplaceSourceIds и записывает cnt на setter

Класс, который изменяется, выглядит следующим образом:

@Cache
class ReferenceDataService {
    private var sourceIds = setOf<Int>()
    private var replaceSourceIds = setOf<Int>(1111)

    private var cnt = 0;
    private var x = 0;

    fun getReplaceSourceIds():Set<Int> {
        return replaceSourceIds
    }

    fun getSourceIds():Set<Int> {
        return sourceIds
    }

    fun incr(by:Int) {
        cnt = cnt+by
    }

    fun setter(by:Int) {
        x = 1000+by
    }

    fun getX():Int {
        return x
    }

    fun doesSourceExists(id:Int):Boolean {
        return sourceIds.contains(id)
    }

Я был ожидая, что если я вызову doesSourceExists(1111), он вернет true, но он вернет false. Кроме того, getSourceIds() вернет пустой набор

Точно так же я ожидал, если я получу доступ к getX() после вызова incr(1), он вернет 1001, но это не так.

Я проверил, что подстановка полей работает должным образом, то есть следующий код работает в соответствии с моим ожиданием

builder = builder.visit(MemberSubstitution.strict()
                                    .field(named("sourceIds")).onRead()
                                    .replaceWith(ReferenceDataService.class.getDeclaredField("replaceSourceIds"))
                                    .on(any()));

Может кто-нибудь, пожалуйста, помогите мне с тем, что я делаю здесь не так с заменой метода?

...