У меня есть вариант использования, когда я хочу заменить чтение и запись поля вызовом метода. У меня есть следующий код агента для достижения того же:
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()));
Может кто-нибудь, пожалуйста, помогите мне с тем, что я делаю здесь не так с заменой метода?