【问题标题】:How can I make delegate class non-public when delegating methods of an interface in another package?在另一个包中委托接口的方法时,如何使委托类不公开?
【发布时间】:2017-02-21 20:36:25
【问题描述】:

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

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 公开为库中的公共类型;我宁愿让它保持包私有。这样做的一种方法是在运行时在库包中生成ImplDelegate 的公共子类,它使用公共桥接方法代理所有包私有方法并将其用作委托。我看过TypeProxy,但我对 ByteBuddy 还不够熟悉,还不知道辅助类型机制是否适合这个。

有没有办法生成运行时代理,以某种方式实现桥接方法,以便我可以隐藏委托实现?

【问题讨论】:

    标签: java byte-buddy


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 感谢您的帮助!我想我更喜欢第一种选择;让接口记录委托和实现之间的协议可能不是一个坏主意。
    猜你喜欢
    • 2015-01-30
    • 1970-01-01
    • 2015-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多