From a1c1e32947b6240a70ada8aac7909d3eecffa864 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 28 Nov 2024 11:04:50 +0000 Subject: [PATCH] Call spring.factories customizers in the same way as one from props Previously, customizers loaded from spring.factories were called using LambdaSafe. This resulted in customizers with a generic type more specific than Object being ignored. A customizer loaded from the logging.structured.json.customizer property was not affected as it was called directly rather than through LambdaSafe. This commit aligns the way in which customizers loaded from spring.factories are called with the way in which any customizer specified using the logging.structured.json.customizer property is called. Closes gh-43312 --- .../StructuredLogFormatterFactory.java | 8 ++-- .../StructuredLogFormatterFactoryTests.java | 46 ++++++++++++++++--- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactory.java index e5fc4c3218d..22e3c6d872c 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactory.java @@ -27,7 +27,6 @@ import org.springframework.boot.json.JsonWriter.Members; import org.springframework.boot.util.Instantiator; import org.springframework.boot.util.Instantiator.AvailableParameters; import org.springframework.boot.util.Instantiator.FailureHandler; -import org.springframework.boot.util.LambdaSafe; import org.springframework.core.GenericTypeResolver; import org.springframework.core.env.Environment; import org.springframework.core.io.support.SpringFactoriesLoader; @@ -108,11 +107,12 @@ public class StructuredLogFormatterFactory { ArgumentResolver.from(this.instantiator::getArg)); } - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) private void invokeCustomizers(List> customizers, Members members) { - LambdaSafe.callbacks(StructuredLoggingJsonMembersCustomizer.class, customizers, members) - .invoke((customizer) -> customizer.customize(members)); + for (StructuredLoggingJsonMembersCustomizer customizer : customizers) { + ((StructuredLoggingJsonMembersCustomizer) customizer).customize(members); + } } /** diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactoryTests.java index c91a75f0acd..cc0bbc8d043 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactoryTests.java @@ -20,6 +20,7 @@ import java.util.List; import org.junit.jupiter.api.Test; +import org.springframework.boot.json.JsonWriter.Members; import org.springframework.boot.json.JsonWriter.ValueProcessor; import org.springframework.boot.logging.structured.StructuredLogFormatterFactory.CommonFormatters; import org.springframework.boot.util.Instantiator.AvailableParameters; @@ -104,18 +105,49 @@ class StructuredLogFormatterFactoryTests { } @Test - void getInjectCustomizers() { + void getInjectStringMembersCustomizer() { this.environment.setProperty("logging.structured.json.rename.spring", "test"); SpringFactoriesLoader factoriesLoader = mock(SpringFactoriesLoader.class); - StructuredLoggingJsonMembersCustomizer customizer = (members) -> members - .applyingValueProcessor(ValueProcessor.of(String.class, String::toUpperCase)); - given(factoriesLoader.load(any(), any(ArgumentResolver.class))).willReturn(List.of(customizer)); + given(factoriesLoader.load(any(), any(ArgumentResolver.class))) + .willReturn(List.of(new StringMembersStructuredLoggingJsonMembersCustomizer())); StructuredLogFormatterFactory factory = new StructuredLogFormatterFactory<>(factoriesLoader, LogEvent.class, this.environment, this::addAvailableParameters, this::addCommonFormatters); - CutomizedFormatter formatter = (CutomizedFormatter) factory.get(CutomizedFormatter.class.getName()); + CustomizedFormatter formatter = (CustomizedFormatter) factory.get(CustomizedFormatter.class.getName()); assertThat(formatter.format(new LogEvent())).contains("\"test\":\"BOOT\""); } + @Test + void getInjectObjectMembersCustomizer() { + this.environment.setProperty("logging.structured.json.rename.spring", "test"); + SpringFactoriesLoader factoriesLoader = mock(SpringFactoriesLoader.class); + given(factoriesLoader.load(any(), any(ArgumentResolver.class))) + .willReturn(List.of(new ObjectMembersStructuredLoggingJsonMembersCustomizer())); + StructuredLogFormatterFactory factory = new StructuredLogFormatterFactory<>(factoriesLoader, + LogEvent.class, this.environment, this::addAvailableParameters, this::addCommonFormatters); + CustomizedFormatter formatter = (CustomizedFormatter) factory.get(CustomizedFormatter.class.getName()); + assertThat(formatter.format(new LogEvent())).contains("\"test\":\"BOOT\""); + } + + static class StringMembersStructuredLoggingJsonMembersCustomizer + implements StructuredLoggingJsonMembersCustomizer { + + @Override + public void customize(Members members) { + members.applyingValueProcessor(ValueProcessor.of(String.class, String::toUpperCase)); + } + + } + + static class ObjectMembersStructuredLoggingJsonMembersCustomizer + implements StructuredLoggingJsonMembersCustomizer { + + @Override + public void customize(Members members) { + members.applyingValueProcessor(ValueProcessor.of(String.class, String::toUpperCase)); + } + + } + static class LogEvent { } @@ -167,9 +199,9 @@ class StructuredLogFormatterFactoryTests { } - static class CutomizedFormatter extends JsonWriterStructuredLogFormatter { + static class CustomizedFormatter extends JsonWriterStructuredLogFormatter { - CutomizedFormatter(StructuredLoggingJsonMembersCustomizer customizer) { + CustomizedFormatter(StructuredLoggingJsonMembersCustomizer customizer) { super((members) -> members.add("spring", "boot"), customizer); }