У меня есть интерфейс, подобный этому:
public interface Getter {
Object get(Params params);
}
, который я реализую с помощью рефлексивного вызова другого метода:
public class GetterImpl implements Getter {
private final Object target;
private final Method method; //doStuff method
public GetterImpl(Object target, Method method) {
this.target = target;
this.method = method;
}
@Override
public Object get(Params params) {
//both the target and arguments depend on Params
return method.invoke(chooseTarget(params), prepareArgs(params));
}
private Object chooseTarget(Params params) {
if (params.getTargetOverride() != null) {
return params.getTargetOverride();
}
return target;
}
private Object[] prepareArgs(Params params) {
...
}
}
Возможно ли вместо этого сгенерировать реализацию класса Getter
с эквивалентными логиками c но без отражения? По сути, такой класс:
public class GeneratedGetterImpl implements Getter {
...
@Override
public Object get(Params params) {
//somehow call doStuff directly (different method for each generated impl)
return target.doStuff(prepareArgs(params));
}
}
Я собираюсь использовать Byte Buddy для генерации такого класса на лету, но все примеры предоставляют какой-то статически известный метод-перехватчик и никогда не делегируют динамически выбранная цель и метод.
Это явно не тривиальная задача, но можно ли это сделать с помощью Byte Buddy? Или другая библиотека?
ОБНОВЛЕНИЕ:
Вот моя лучшая попытка:
Target target = new Target();
Method method = Target.class.getMethod("doStuff", Book.class);
//Helper class that computes the new arguments based on the original
Prepare prepare = new Prepare();
Method doPrep = Prepare.class.getMethod("doPrep", Params.class);
Getter getter = (Getter) new ByteBuddy()
.subclass(Object.class)
.implement(Getter.class)
.method(named("get")).intercept(
MethodCall.invoke(method).on(target)
.withMethodCall(
MethodCall.invoke(doPrep).on(prepare).withAllArguments()
))
.make()
.load(getClass().getClassLoader())
.getLoaded()
.newInstance();
public static class Prepare {
public Book doPrep(Params params) {
return new Book(params.getTitle());
}
}
Это делает то, что я хочу, но только если целевой метод принимает 1 аргумент (Book
в моем случае). Я пытаюсь выяснить, как заставить его возвращать массив, который я затем распространяю при вызове целевого метода.
Например,
public static class Prepare {
//returns all the arguments
public Object[] doPrep(Params params) {
return new Object[] { new Book(params.getTitle()) };
}
}