1010import java .util .Arrays ;
1111import java .util .Comparator ;
1212import java .util .Optional ;
13+ import java .util .ServiceConfigurationError ;
1314import java .util .ServiceLoader ;
1415import java .util .stream .Stream ;
1516
@@ -21,38 +22,38 @@ private IntegrationsLoader() {
2122 }
2223
2324 /**
24- * Loads the best suited service, i.e. the one with the highest priority that is supported.
25+ * Loads the best suited service provider , i.e. the one with the highest priority that is supported.
2526 * <p>
2627 * If two services are available with the same priority, it is unspecified which one will be returned.
2728 *
2829 * @param clazz Service class
2930 * @param <T> Type of the service
30- * @return Highest priority service or empty if no supported service was found
31+ * @return Highest priority service provider or empty if no supported service provider was found
3132 */
3233 public static <T > Optional <T > load (Class <T > clazz ) {
3334 return loadAll (clazz ).findFirst ();
3435 }
3536
3637 /**
37- * Loads all suited services ordered by priority in descending order.
38+ * Loads all suited service providers ordered by priority in descending order.
3839 *
3940 * @param clazz Service class
4041 * @param <T> Type of the service
41- * @return An ordered stream of all suited service candidates
42+ * @return An ordered stream of all suited service providers
4243 */
4344 public static <T > Stream <T > loadAll (Class <T > clazz ) {
4445 return ServiceLoader .load (clazz , ClassLoaderFactory .forPluginDir ())
4546 .stream ()
46- .peek (service -> logFoundService (clazz , service .type ()))
47+ .peek (serviceProvider -> logFoundServiceProvider (clazz , serviceProvider .type ()))
4748 .filter (IntegrationsLoader ::isSupportedOperatingSystem )
4849 .filter (IntegrationsLoader ::passesStaticAvailabilityCheck )
4950 .sorted (Comparator .comparingInt (IntegrationsLoader ::getPriority ).reversed ())
50- .map ( ServiceLoader . Provider :: get )
51+ .flatMap ( IntegrationsLoader :: instantiateServiceProvider )
5152 .filter (IntegrationsLoader ::passesInstanceAvailabilityCheck )
5253 .peek (impl -> logServiceIsAvailable (clazz , impl .getClass ()));
5354 }
5455
55- private static void logFoundService (Class <?> apiType , Class <?> implType ) {
56+ private static void logFoundServiceProvider (Class <?> apiType , Class <?> implType ) {
5657 if (LOG .isDebugEnabled ()) {
5758 LOG .debug ("{}: Found implementation: {} in jar {}" , apiType .getSimpleName (), implType .getName (), implType .getProtectionDomain ().getCodeSource ().getLocation ().getPath ());
5859 }
@@ -68,18 +69,30 @@ private static boolean isSupportedOperatingSystem(ServiceLoader.Provider<?> prov
6869 return annotations .length == 0 || Arrays .stream (annotations ).anyMatch (OperatingSystem .Value ::isCurrent );
6970 }
7071
72+ private static <T > Stream <T > instantiateServiceProvider (ServiceLoader .Provider <T > provider ) {
73+ try {
74+ return Stream .of (provider .get ());
75+ } catch (ServiceConfigurationError err ) {
76+ //ServiceLoader.Provider::get throws this error if (from javadoc)
77+ // * the public static "provider()" method of a provider factory returns null
78+ // * the service provider cannot be instantiated due to an error/throw
79+ LOG .warn ("Unable to load service provider {}." , provider .type ().getName (), err );
80+ return Stream .empty ();
81+ }
82+ }
83+
7184 private static boolean passesStaticAvailabilityCheck (ServiceLoader .Provider <?> provider ) {
7285 return passesStaticAvailabilityCheck (provider .type ());
7386 }
7487
7588 @ VisibleForTesting
7689 static boolean passesStaticAvailabilityCheck (Class <?> type ) {
77- return passesAvailabilityCheck (type , null );
90+ return silentlyPassesAvailabilityCheck (type , null );
7891 }
7992
8093 @ VisibleForTesting
8194 static boolean passesInstanceAvailabilityCheck (Object instance ) {
82- return passesAvailabilityCheck (instance .getClass (), instance );
95+ return silentlyPassesAvailabilityCheck (instance .getClass (), instance );
8396 }
8497
8598 private static void logServiceIsAvailable (Class <?> apiType , Class <?> implType ) {
@@ -88,6 +101,15 @@ private static void logServiceIsAvailable(Class<?> apiType, Class<?> implType) {
88101 }
89102 }
90103
104+ private static <T > boolean silentlyPassesAvailabilityCheck (Class <? extends T > type , @ Nullable T instance ) {
105+ try {
106+ return passesAvailabilityCheck (type , instance );
107+ } catch (ExceptionInInitializerError | NoClassDefFoundError | RuntimeException e ) {
108+ LOG .warn ("Unable to load service provider {}." , type .getName (), e );
109+ return false ;
110+ }
111+ }
112+
91113 private static <T > boolean passesAvailabilityCheck (Class <? extends T > type , @ Nullable T instance ) {
92114 if (!type .isAnnotationPresent (CheckAvailability .class )) {
93115 return true ; // if type is not annotated, skip tests
0 commit comments