In my library, I'm generating implementations of client-provided interfaces (annotated with custom directives from the library). I use MethodDelegation
to intercept interface methods and forward them to an instance of a delegate class defined in a library package:
package library.pkg;
class ImplBase { }
public class ImplDelegate {
final ImplContext context;
ImplDelegate(ImplContext ctx) {
this.context = ctx;
}
public void impl(
@CustomName String name,
@CustomTags String[] tags,
@AllArguments Object[] args) {
// do things here
}
}
static <T> T implClient(Class<T> clientType) {
MethodDelegation delegation = MethodDelegation
.to(new ImplDelegate(new ImplContext(clientType)))
.filter(not(isDeclaredBy(Object.class)))
.appendParameterBinder(ParameterBinders.CustomTags.binder)
.appendParameterBinder(ParameterBinders.CustomName.binder);
Class<? extends ImplBase> implClass =
new ByteBuddy()
.subclass(ImplBase.class)
.name(String.format("%s$Impl$%d", clientType.getName(), id++))
.implement(clientType)
.method(isDeclaredBy(clientType).and(isVirtual()).and(returns(VOID)))
.intercept(delegation)
.make()
.load(clientType.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
return clientType.cast(implClass.newInstance());
}
// In client code, get an instance of the interface and use it.
package client.pkg;
interface Client {
void operationA(String p1, long p2);
void operationB(String... p1);
}
Client client = implClient(Client.class);
client.operationA("A", 1);
This works, but it exposes ImplDelegate
as a public type from the library; I'd rather have it stay package-private. One way of doing this would be to generate a public subclass of ImplDelegate
in the library package at runtime that proxies all package-private methods with public bridge methods and use that as the delegate. I've looked at TypeProxy
but I'm not familiar enough with ByteBuddy yet to see if the auxiliary type mechanism is a good fit for this.
Is there a way to generate runtime proxies that implement bridge methods in a way so I can hide delegate implementations?