简体   繁体   English

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

[英]How can I make delegate class non-public when delegating methods of an interface in another package?

In my library, I'm generating implementations of client-provided interfaces (annotated with custom directives from the library).在我的库中,我正在生成客户端提供的接口的实现(使用库中的自定义指令进行注释)。 I use MethodDelegation to intercept interface methods and forward them to an instance of a delegate class defined in a library package:我使用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);

This works, but it exposes ImplDelegate as a public type from the library;这有效,但它将ImplDelegate作为库中的公共类型公开; I'd rather have it stay package-private.我宁愿让它保持包私有。 One way of doing this would be to generate a public subclass of ImplDelegate in the library package at runtime that proxies all package-private methods with public bridge methods and use that as the delegate.这样做的一种方法是在运行时在库包中生成ImplDelegate的公共子类,该子类使用公共桥接方法代理所有包私有方法并将其用作委托。 I've looked at TypeProxy but I'm not familiar enough with ByteBuddy yet to see if the auxiliary type mechanism is a good fit for this.我已经看过TypeProxy但我对 ByteBuddy 还不够熟悉,还没有看到辅助类型机制是否适合于此。

Is there a way to generate runtime proxies that implement bridge methods in a way so I can hide delegate implementations?有没有办法生成以某种方式实现桥接方法的运行时代理,以便我可以隐藏委托实现?

The delegate type needs to be visible to the class that is invoking it.委托类型需要对调用它的类可见。 You have only two possibilities:你只有两种可能:

  1. Create a type in the same package as the interceptor.在与拦截器相同的包中创建一个类型。 Make sure you are injecting the generated class in the interceptor's class loader, a package-private type is only visible to classes of the same package in the same class loader.确保在拦截器的类加载器中注入生成的类,包私有类型仅对同一个类加载器中同一个包的类可见。 This way, you can however only implement public interfaces.这样,您只能实现公共接口。
  2. At runtime, subclass your interceptor and make sure all interceptor methods are public.在运行时,子类化拦截器并确保所有拦截器方法都是公共的。 Byte Buddy, by default, generates a public subclass:默认情况下,Byte Buddy 会生成一个公共子类:

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

    The above type will be public such that you can now delegate to this instance, even if ImplDelegate is package-private.上面的类型将是公开的,这样您现在可以委托给这个实例,即使ImplDelegate是包私有的。 Note however, that this only affects compile-time visibility, at runtime, the subclass of ImplDelegate is visible to any type.但是请注意,这仅影响编译时可见性,在运行时, ImplDelegate的子类对任何类型都是可见的。 (The constructor does however remain package-private, even for the subclass.) (然而,构造函数确实保持包私有,即使对于子类也是如此。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM