在另一个包中委托接口方法时,如何使委托 class 非 public?
How can I make delegate class non-public when delegating methods of an interface in another package?
在我的库中,我正在生成客户端提供的接口的实现(使用库中的自定义指令进行注释)。我使用 MethodDelegation
拦截接口方法并将它们转发给在库包中定义的委托实例 class:
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);
这行得通,但是它将 ImplDelegate
作为库中的 public 类型公开;我宁愿让它保持包私有。一种方法是在运行时在库包中生成 public subclass of ImplDelegate
,它使用 public 桥接方法代理所有包私有方法并使用那作为代表。我看过 TypeProxy
但我对 ByteBuddy 还不够熟悉,还不知道辅助类型机制是否适合这个。
有没有办法生成以某种方式实现桥接方法的运行时代理,以便我可以隐藏委托实现?
委托类型需要对调用它的 class 可见。你只有两种可能:
- 在与拦截器相同的包中创建一个类型。确保在拦截器的 class 加载器中注入生成的 class,包私有类型仅对同一 class 加载器中同一包的 classes 可见.这样,您只能实现 public 接口。
在运行时,subclass 你的拦截器并确保所有拦截器方法都是 public。字节好友,默认生成一个public subclass:
Object delegate = new ByteBuddy()
.subclass(ImplDelegate.class)
.make()
.load(ImplDelegate.class.getClassLoader())
.getLoaded()
.newInstance();
上面的类型将是 public 这样你现在可以委托给这个实例,即使 ImplDelegate
是包私有的。但是请注意,这只会影响编译时可见性,在运行时,ImplDelegate
的 subclass 对任何类型都是可见的。 (然而,构造函数确实保持包私有,即使对于 subclass。)
在我的库中,我正在生成客户端提供的接口的实现(使用库中的自定义指令进行注释)。我使用 MethodDelegation
拦截接口方法并将它们转发给在库包中定义的委托实例 class:
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);
这行得通,但是它将 ImplDelegate
作为库中的 public 类型公开;我宁愿让它保持包私有。一种方法是在运行时在库包中生成 public subclass of ImplDelegate
,它使用 public 桥接方法代理所有包私有方法并使用那作为代表。我看过 TypeProxy
但我对 ByteBuddy 还不够熟悉,还不知道辅助类型机制是否适合这个。
有没有办法生成以某种方式实现桥接方法的运行时代理,以便我可以隐藏委托实现?
委托类型需要对调用它的 class 可见。你只有两种可能:
- 在与拦截器相同的包中创建一个类型。确保在拦截器的 class 加载器中注入生成的 class,包私有类型仅对同一 class 加载器中同一包的 classes 可见.这样,您只能实现 public 接口。
在运行时,subclass 你的拦截器并确保所有拦截器方法都是 public。字节好友,默认生成一个public subclass:
Object delegate = new ByteBuddy() .subclass(ImplDelegate.class) .make() .load(ImplDelegate.class.getClassLoader()) .getLoaded() .newInstance();
上面的类型将是 public 这样你现在可以委托给这个实例,即使
ImplDelegate
是包私有的。但是请注意,这只会影响编译时可见性,在运行时,ImplDelegate
的 subclass 对任何类型都是可见的。 (然而,构造函数确实保持包私有,即使对于 subclass。)