java - 在委托(delegate)另一个包中的接口(interface)的方法时,如何使委托(delegate)类成为非公开的?

标签 java byte-buddy

在我的库中,我正在生成客户端提供的接口(interface)的实现(用库中的自定义指令进行注释)。我使用 MethodDelegation 来拦截接口(interface)方法并将它们转发到库包中定义的委托(delegate)类的实例:

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)类型;我宁愿让它保持包私有(private)。实现此目的的一种方法是在运行时在库包中生成 ImplDelegate 的公共(public)子类,该子类使用公共(public)桥接方法代理所有包私有(private)方法,并将其用作委托(delegate)。我研究过 TypeProxy,但我对 ByteBuddy 还不够熟悉,还不知道辅助类型机制是否适合于此。

有没有办法生成运行时代理来实现桥接方法,以便我可以隐藏委托(delegate)实现?

最佳答案

委托(delegate)类型需要对调用它的类可见。你只有两种可能性:

  1. 在与拦截器相同的包中创建一个类型。确保将生成的类注入(inject)拦截器的类加载器中,包私有(private)类型仅对同一类加载器中同一包的类可见。但是,这样您就只能实现公共(public)接口(interface)。
  2. 在运行时,子类化您的拦截器并确保所有拦截器方法都是公共(public)的。 Byte Buddy默认生成一个公共(public)子类:

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

    上述类型将是公共(public)的,这样您现在就可以委托(delegate)给此实例,即使 ImplDelegate 是包私有(private)的。但请注意,这仅影响编译时可见性,在运行时,ImplDelegate 的子类对任何类型都可见。 (但是,构造函数仍然是包私有(private)的,即使对于子类也是如此。)

关于java - 在委托(delegate)另一个包中的接口(interface)的方法时,如何使委托(delegate)类成为非公开的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40008819/

相关文章:

java - Maven java项目中文件的源编码

java - 递归代码中的困惑

java - 为什么带有字符串的对象打印为空?

java - 向类添加字段导致 "<constructor> does not define an index 2"异常

java - 如何使用 Byte-Buddy 从接口(interface)构建 Java 类的具体实现?

java - 是否有运行时代理创建库支持保留代理类的注释?

Java > Array-2 > ZeroMax

java - 如何通过 REST (JAX-RS) 在 web.xml 中声明多个包?

java - 如何使用 Byte Buddy 和 @Advice 捕获返回数据?

hibernate - ByteBuddy 在 Hibernate 中的性能