If this is not Android, returns all available implementations discovered via ServiceLoader. If this is Android, returns all available implementations in hardcoded. The list is sorted in descending priority order. serviceLoader should be created with {@code ServiceLoader.l
(
Class<T> klass,
Iterator<T> serviceLoader,
Supplier<Iterable<Class<?>>> hardcoded,
final PriorityAccessor<T> priorityAccessor)
| 43 | * will keep the constructors for the provider classes. |
| 44 | */ |
| 45 | public static <T> List<T> loadAll( |
| 46 | Class<T> klass, |
| 47 | Iterator<T> serviceLoader, |
| 48 | Supplier<Iterable<Class<?>>> hardcoded, |
| 49 | final PriorityAccessor<T> priorityAccessor) { |
| 50 | Iterator<T> candidates; |
| 51 | if (serviceLoader instanceof ListIterator) { |
| 52 | // A rewriting tool has replaced the ServiceLoader with a List of some sort (R8 uses |
| 53 | // ArrayList, AppReduce uses singletonList). We prefer to use such iterators on Android as |
| 54 | // they won't need reflection like the hard-coded list does. In addition, the provider |
| 55 | // instances will have already been created, so it seems we should use them. |
| 56 | // |
| 57 | // R8: https://r8.googlesource.com/r8/+/490bc53d9310d4cc2a5084c05df4aadaec8c885d/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java |
| 58 | // AppReduce: service_loader_pass.cc |
| 59 | candidates = serviceLoader; |
| 60 | } else if (isAndroid(klass.getClassLoader())) { |
| 61 | // Avoid getResource() on Android, which must read from a zip which uses a lot of memory |
| 62 | candidates = getCandidatesViaHardCoded(klass, hardcoded.get()).iterator(); |
| 63 | } else if (!serviceLoader.hasNext()) { |
| 64 | // Attempt to load using the context class loader and ServiceLoader. |
| 65 | // This allows frameworks like http://aries.apache.org/modules/spi-fly.html to plug in. |
| 66 | candidates = ServiceLoader.load(klass).iterator(); |
| 67 | } else { |
| 68 | candidates = serviceLoader; |
| 69 | } |
| 70 | List<T> list = new ArrayList<>(); |
| 71 | while (candidates.hasNext()) { |
| 72 | T current = candidates.next(); |
| 73 | if (!priorityAccessor.isAvailable(current)) { |
| 74 | continue; |
| 75 | } |
| 76 | list.add(current); |
| 77 | } |
| 78 | |
| 79 | // Sort descending based on priority. If priorities are equal, compare the class names to |
| 80 | // get a reliable result. |
| 81 | Collections.sort(list, Collections.reverseOrder(new Comparator<T>() { |
| 82 | @Override |
| 83 | public int compare(T f1, T f2) { |
| 84 | int pd = priorityAccessor.getPriority(f1) - priorityAccessor.getPriority(f2); |
| 85 | if (pd != 0) { |
| 86 | return pd; |
| 87 | } |
| 88 | return f1.getClass().getName().compareTo(f2.getClass().getName()); |
| 89 | } |
| 90 | })); |
| 91 | return Collections.unmodifiableList(list); |
| 92 | } |
| 93 | |
| 94 | /** |
| 95 | * Returns true if the {@link ClassLoader} is for android. |