I currently working on a JPMS project and would like to be able to cache the Providers retrieved on ServiceLoader.load() to be able to use their get() method later for a new set of service instances - without a reference to the ServiceLoader necessarily. In short, retrieve a collection of them from some map and return them as ServiceLoader.Provider<.T>
Even shorter, how do I do:
public static <T> List<ServiceLoader.Provider<T>> getProvidersOf(Class<T> clazz){
return (List<ServiceLoader.Provider<T>>) servicesProvidersMap.get(clazz);
}
For a map: Map<Class<?>, List<ServiceLoader.Provider<?>>> servicesProvidersMap = new ConcurrentHashMap<>();
What have I tried:
- Cast it to object then back to Provider<.T>
- Used the iterator, but that returns new T instances, not Provider<.T>
- Not using the streams api. However, "for" uses the iterator.
What does work, but isn't what I'm looking for:
- Individually casting each provider when adding them to a new list instance. But that is not in line with "having the value pre-calculated and ready to go".
.
public static <T> List<ServiceLoader.Provider<T>> getProvidersOf(Class<T> clazz){
List<ServiceLoader.Provider<?>> cached = servicesProvidersMap.get(clazz);
if(cached != null) {
List<ServiceLoader.Provider<T>> casted = new CopyOnWriteArrayList<>();
cached.forEach(provider -> casted.add((ServiceLoader.Provider<T>) provider));
return casted;
}
[...on empty cache]
}
- Caching the loader and re-retrieving the Providers every call. Same as above for my purposes really.
.
List<ServiceLoader.Provider<T>> hereWeGoAgain = getLoaderFor(clazz)
.stream()
.collect(Collectors.toCollection(CopyOnWriteArrayList::new));
I understand that a ServiceLoader.Provider instance may be some transition object, and not intended to be kept around, however, it would provide me a great deal of options and flexibility if it was possible.