Java模块系统:“提供”通用接口

Mar*_*tto 5 java generics java-module java-12

我正在尝试Java模块系统。我正在尝试将ServiceLoader用于通用接口。它可以工作,但是我在module-info中收到警告。这是我的最小代码

module testProvideWith {
  provides ServiceGeneric with SString;
  uses ServiceGeneric;
}
public interface ServiceGeneric<T> {
  T getT();
}
public class SString implements ServiceGeneric<String>{
  public String getT() {return "Hello";}
}
Run Code Online (Sandbox Code Playgroud)

尝试时收到警告我并不感到惊讶

ServiceGeneric<String> serv=ServiceLoader.load(ServiceGeneric.class).findFirst().get();
Run Code Online (Sandbox Code Playgroud)

我知道通用擦除,我知道我必须使用注释或其他技巧来注释正确的服务。但是...我没有找到所有通用服务。我希望能够写类似

module testProvideWith {
  provides ServiceGeneric<String> with SString;
  uses ServiceGeneric<String>;
  //more cases could be added
}
...
ServiceLoader.load(ServiceGeneric.class,String.class)
Run Code Online (Sandbox Code Playgroud)

模块和加载程序在哪里协作以跟踪可用的通用版本..但是...什么都没有...没有人考虑过这种可能性...我想念什么吗?

A24*_*248 0

正如您所发现的,服务提供商并不是为通用服务而设计的。但是,您可以通过在服务提供者实现中编码通用参数以及一些管理代码来解决此限制。

具体来说,您的服务提供商应该产生Class他们的通用参数,例如通过 getter 方法。

// I prefer to define a non-generic service for use with ServiceLoader. 
// Strictly speaking, this interface is auxiliary.
public interface ServiceBundle {
  List<ServiceGeneric<?>> providers();
}

public interface ServiceGeneric<T> {
  Class<T> type();

  T getT();
}

public class ServiceString implements ServiceGeneric<String>{
  public Class<String> type() {
    return String.class;
  }
  public String getT() {
    return "Hello";
  }
}
Run Code Online (Sandbox Code Playgroud)

然后您应该能够迭代ServiceLoader.load(ServiceBundle.class)并将您的服务提供者放入Map<Class<?>, ServiceGeneric<?>>供以后使用。

Map<Class<?>, ServiceGeneric<?>> providers = new HashMap<>();
for (ServiceBundle bundle : ServiceLoader.load(ServiceBundle.class)) {
  for (ServiceGeneric<?> provider : bundle.providers()) {
    providers.put(provider.type(), provider);
  }
}
providers = Map.copyOf(providers); // freeze the map

//
// ...
//

public class GenericServiceManager {

  public <T> ServiceGeneric<T> getProvider(Class<T> type) {
    // Assuming everything is set up correctly, this cast will be safe
    return providers.get(type);
  }
}
Run Code Online (Sandbox Code Playgroud)