diff --git a/cf-java-logging-support-core/src/main/java/com/sap/hcp/cf/logging/common/serialization/ContextFieldSupplierServiceLoader.java b/cf-java-logging-support-core/src/main/java/com/sap/hcp/cf/logging/common/serialization/ContextFieldSupplierServiceLoader.java index c31e20ca..687f9209 100644 --- a/cf-java-logging-support-core/src/main/java/com/sap/hcp/cf/logging/common/serialization/ContextFieldSupplierServiceLoader.java +++ b/cf-java-logging-support-core/src/main/java/com/sap/hcp/cf/logging/common/serialization/ContextFieldSupplierServiceLoader.java @@ -1,18 +1,40 @@ package com.sap.hcp.cf.logging.common.serialization; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.ArrayList; +import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.stream.Collectors; import java.util.stream.Stream; public class ContextFieldSupplierServiceLoader { + private static Logger logger() { + return LoggerFactory.getLogger(ContextFieldSupplierServiceLoader.class); + } + private ContextFieldSupplierServiceLoader() { } public static ArrayList addFieldSuppliers(Stream original, Class clazz) { - Stream spiSuppliers = ServiceLoader.load(clazz).stream().map(ServiceLoader.Provider::get).sorted(); + Stream spiSuppliers = loadSafely(clazz); return Stream.concat(original, spiSuppliers).sorted().collect(Collectors.toCollection(ArrayList::new)); } + private static Stream loadSafely(Class clazz) { + ArrayList result = new ArrayList<>(); + var iterator = ServiceLoader.load(clazz).iterator(); + while (true) { + try { + if (!iterator.hasNext()) break; + result.add(iterator.next()); + } catch (ServiceConfigurationError e) { + logger().warn("Skipping invalid SPI provider for {}: {}", clazz.getName(), e.getMessage()); + } + } + return result.stream(); + } + } diff --git a/cf-java-logging-support-core/src/test/java/com/sap/hcp/cf/logging/common/serialization/ContextFieldSupplierServiceLoaderTest.java b/cf-java-logging-support-core/src/test/java/com/sap/hcp/cf/logging/common/serialization/ContextFieldSupplierServiceLoaderTest.java new file mode 100644 index 00000000..107e97fb --- /dev/null +++ b/cf-java-logging-support-core/src/test/java/com/sap/hcp/cf/logging/common/serialization/ContextFieldSupplierServiceLoaderTest.java @@ -0,0 +1,39 @@ +package com.sap.hcp.cf.logging.common.serialization; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Map; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +class ContextFieldSupplierServiceLoaderTest { + + public static class ValidSupplier implements ContextFieldSupplier { + @Override + public Map get() { + return Collections.emptyMap(); + } + } + + @Test + void doesNotThrowWhenSpiProviderIsInvalid() { + assertThatCode(() -> ContextFieldSupplierServiceLoader.addFieldSuppliers(Stream.empty(), + ContextFieldSupplier.class)) + .doesNotThrowAnyException(); + } + + @Test + void skipsInvalidSpiProviderAndKeepsValidOnes() { + ValidSupplier valid = new ValidSupplier(); + + ArrayList result = ContextFieldSupplierServiceLoader.addFieldSuppliers( + Stream.of(valid), ContextFieldSupplier.class); + + assertThat(result).contains(valid); + } + +} diff --git a/cf-java-logging-support-core/src/test/resources/META-INF/services/com.sap.hcp.cf.logging.common.serialization.ContextFieldSupplier b/cf-java-logging-support-core/src/test/resources/META-INF/services/com.sap.hcp.cf.logging.common.serialization.ContextFieldSupplier new file mode 100644 index 00000000..03f5a586 --- /dev/null +++ b/cf-java-logging-support-core/src/test/resources/META-INF/services/com.sap.hcp.cf.logging.common.serialization.ContextFieldSupplier @@ -0,0 +1,2 @@ +# Intentionally invalid entry (does not implement ContextFieldSupplier) to trigger a ServiceConfigurationError for testing. +com.sap.hcp.cf.logging.common.helper.StacktraceGenerator