有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在另一个包中委托接口的方法时,如何使委托类成为非公共类?

在我的库中,我正在生成客户端提供的接口的实现(用库中的自定义指令注释)。我使用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,但我对字节库还不够熟悉,所以还不知道辅助类型机制是否适合这种情况

有没有一种方法可以生成运行时代理来实现桥接方法,这样我就可以隐藏委托实现


共 (1) 个答案

  1. # 1 楼答案

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

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

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

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