在另一个包中委托接口方法时,如何使委托 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 可见。你只有两种可能:

  1. 在与拦截器相同的包中创建一个类型。确保在拦截器的 class 加载器中注入生成的 class,包私有类型仅对同一 class 加载器中同一包的 classes 可见.这样,您只能实现 public 接口。
  2. 在运行时,subclass 你的拦截器并确保所有拦截器方法都是 public。字节好友,默认生成一个public subclass:

    Object delegate = new ByteBuddy()
      .subclass(ImplDelegate.class)
      .make()
      .load(ImplDelegate.class.getClassLoader())
      .getLoaded()
      .newInstance();
    

    上面的类型将是 public 这样你现在可以委托给这个实例,即使 ImplDelegate 是包私有的。但是请注意,这只会影响编译时可见性,在运行时,ImplDelegate 的 subclass 对任何类型都是可见的。 (然而,构造函数确实保持包私有,即使对于 subclass。)