diff --git a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java index bea63d57a73c..6444f3f0a254 100644 --- a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java +++ b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java @@ -16,11 +16,7 @@ package org.springframework.boot.logging.log4j2; -import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLConnection; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; @@ -37,15 +33,11 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.AbstractConfiguration; import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.ConfigurationException; import org.apache.logging.log4j.core.config.ConfigurationFactory; -import org.apache.logging.log4j.core.config.ConfigurationSource; import org.apache.logging.log4j.core.config.LoggerConfig; import org.apache.logging.log4j.core.config.composite.CompositeConfiguration; import org.apache.logging.log4j.core.filter.DenyAllFilter; -import org.apache.logging.log4j.core.net.UrlConnectionFactory; -import org.apache.logging.log4j.core.net.ssl.SslConfiguration; -import org.apache.logging.log4j.core.net.ssl.SslConfigurationFactory; -import org.apache.logging.log4j.core.util.AuthorizationProvider; import org.apache.logging.log4j.core.util.NameUtil; import org.apache.logging.log4j.jul.Log4jBridgeHandler; import org.apache.logging.log4j.status.StatusConsoleListener; @@ -72,7 +64,6 @@ import org.springframework.core.io.ResourceLoader; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; -import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; /** @@ -88,6 +79,8 @@ */ public class Log4J2LoggingSystem extends AbstractLoggingSystem { + private static final org.apache.logging.log4j.Logger STATUS_LOGGER = StatusLogger.getLogger(); + private static final String OPTIONAL_PREFIX = "optional:"; /** @@ -100,41 +93,6 @@ public class Log4J2LoggingSystem extends AbstractLoggingSystem { */ static final String LOG4J_LOG_MANAGER = "org.apache.logging.log4j.jul.LogManager"; - /** - * JSON tree parser used by Log4j 2 (optional dependency). - */ - static final String JSON_TREE_PARSER_V2 = "com.fasterxml.jackson.databind.ObjectMapper"; - - /** - * JSON tree parser embedded in Log4j 3. - */ - static final String JSON_TREE_PARSER_V3 = "org.apache.logging.log4j.kit.json.JsonReader"; - - /** - * Configuration factory for properties files (Log4j 2). - */ - static final String PROPS_CONFIGURATION_FACTORY_V2 = "org.apache.logging.log4j.core.config.properties.PropertiesConfigurationFactory"; - - /** - * Configuration factory for properties files (Log4j 3, optional dependency). - */ - static final String PROPS_CONFIGURATION_FACTORY_V3 = "org.apache.logging.log4j.config.properties.JavaPropsConfigurationFactory"; - - /** - * YAML tree parser used by Log4j 2 (optional dependency). - */ - static final String YAML_TREE_PARSER_V2 = "com.fasterxml.jackson.dataformat.yaml.YAMLMapper"; - - /** - * Configuration factory for YAML files (Log4j 2, embedded). - */ - static final String YAML_CONFIGURATION_FACTORY_V2 = "org.apache.logging.log4j.core.config.yaml.YamlConfigurationFactory"; - - /** - * Configuration factory for YAML files (Log4j 3, optional dependency). - */ - static final String YAML_CONFIGURATION_FACTORY_V3 = "org.apache.logging.log4j.config.yaml.YamlConfigurationFactory"; - private static final SpringEnvironmentPropertySource propertySource = new SpringEnvironmentPropertySource(); static final String ENVIRONMENT_KEY = Conventions.getQualifiedAttributeName(Log4J2LoggingSystem.class, @@ -157,73 +115,69 @@ public class Log4J2LoggingSystem extends AbstractLoggingSystem { private static final Filter FILTER = DenyAllFilter.newBuilder().build(); - public Log4J2LoggingSystem(ClassLoader classLoader) { - super(classLoader); - } + private final LoggerContext loggerContext; - @Override - protected String[] getStandardConfigLocations() { - List locations = new ArrayList<>(); - addLocationsFromProperties(locations); - addStandardLocations(locations); - return StringUtils.toStringArray(locations); + /** + * Create a new {@link Log4J2LoggingSystem} instance. + * @param classLoader the class loader to use. + * @param loggerContext the {@link LoggerContext} to use. + */ + Log4J2LoggingSystem(ClassLoader classLoader, LoggerContext loggerContext) { + super(classLoader); + this.loggerContext = loggerContext; } - private void addLocationsFromProperties(List locations) { - for (String property : List.of("log4j2.configurationFile", "log4j.configuration.location")) { - String propertyDefinedLocation = PropertiesUtil.getProperties().getStringProperty(property); - if (propertyDefinedLocation != null) { - locations.add(propertyDefinedLocation); - } + /** + * Create a new {@link Log4J2LoggingSystem} instance. + * @param classLoader the class loader to use + * @return a new {@link Log4J2LoggingSystem} instance + * @throws IllegalStateException if Log4j Core is not the active Log4j API provider. + */ + private static Log4J2LoggingSystem createLoggingSystem(ClassLoader classLoader) { + org.apache.logging.log4j.spi.LoggerContext loggerContext = LogManager.getContext(classLoader, false); + if (loggerContext instanceof LoggerContext) { + return new Log4J2LoggingSystem(classLoader, (LoggerContext) loggerContext); } + throw new IllegalStateException("Log4j Core is not the active Log4j API provider"); } - private void addStandardLocations(List locations) { - LoggerContext loggerContext = getLoggerContext(); - String contextName = loggerContext.getName(); - List extensions = getStandardConfigExtensions(); - addLocation(locations, "log4j2-test" + contextName, extensions); - addLocation(locations, "log4j2-test", extensions); - addLocation(locations, "log4j2" + contextName, extensions); - addLocation(locations, "log4j2", extensions); - } - - private List getStandardConfigExtensions() { - List extensions = new ArrayList<>(); - // These classes need to be visible by the classloader that loads Log4j Core. - ClassLoader classLoader = LoggerContext.class.getClassLoader(); - // The order of the extensions corresponds to the order in which Log4j Core 2 and - // 3 will try to load them, in decreasing value of @Order. - if (isPresent(classLoader, PROPS_CONFIGURATION_FACTORY_V2) - || isPresent(classLoader, PROPS_CONFIGURATION_FACTORY_V3)) { - extensions.add(".properties"); - } - if (isPresent(classLoader, YAML_CONFIGURATION_FACTORY_V2, YAML_TREE_PARSER_V2) - || isPresent(classLoader, YAML_CONFIGURATION_FACTORY_V3)) { - Collections.addAll(extensions, ".yaml", ".yml"); - } - if (isPresent(classLoader, JSON_TREE_PARSER_V2) || isPresent(classLoader, JSON_TREE_PARSER_V3)) { - Collections.addAll(extensions, ".json", ".jsn"); - } - extensions.add(".xml"); - return extensions; + /** + * {@inheritDoc} + * @deprecated Since 4.0.0, in favor of the {@link ConfigurationFactory} SPI. + */ + @Override + @Deprecated(since = "4.0.0", forRemoval = true) + protected String[] getStandardConfigLocations() { + return new String[] { "log4j2.xml" }; } - private void addLocation(List locations, String location, List extensions) { - extensions.forEach((extension) -> locations.add(location + extension)); + @Override + protected @Nullable String getSelfInitializationConfig() { + Configuration currentConfiguration = getLoggerContext().getConfiguration(); + return getConfigLocation(currentConfiguration); } - private boolean isPresent(ClassLoader classLoader, String... classNames) { - for (String className : classNames) { - if (!isClassAvailable(classLoader, className)) { - return false; - } + @Override + protected @Nullable String getSpringInitializationConfig() { + ConfigurationFactory configurationFactory = ConfigurationFactory.getInstance(); + try { + Configuration springConfiguration = configurationFactory.getConfiguration(getLoggerContext(), "-spring", + null, getClassLoader()); + String configLocation = getConfigLocation(springConfiguration); + return (configLocation != null && configLocation.contains("-spring")) ? configLocation : null; + } + catch (ConfigurationException ex) { + STATUS_LOGGER.warn("Could not load Spring-specific Log4j Core configuration", ex); + return null; } - return true; } - protected boolean isClassAvailable(ClassLoader classLoader, String className) { - return ClassUtils.isPresent(className, classLoader); + private @Nullable String getConfigLocation(Configuration configuration) { + // The location may be: + // - null: if DefaultConfiguration is used (no explicit config loaded) + // - a file path: if provided explicitly by the user + // - a URI: if loaded from the classpath default or a custom location + return configuration.getConfigurationSource().getLocation(); } @Deprecated(since = "4.0.0", forRemoval = true) @@ -335,7 +289,7 @@ private void load(LoggingInitializationContext initializationContext, String loc Environment environment = initializationContext.getEnvironment(); Assert.state(environment != null, "'environment' must not be null"); applySystemProperties(environment, logFile); - loadConfiguration(location, logFile, overrides); + reconfigure(location, overrides); } private List getOverrides(LoggingInitializationContext initializationContext) { @@ -346,66 +300,56 @@ private List getOverrides(LoggingInitializationContext initializationCon return overrides.orElse(Collections.emptyList()); } - /** - * Load the configuration from the given {@code location}, creating a composite using - * the configuration from the given {@code overrides}. - * @param location the location - * @param logFile log file configuration - * @param overrides the overriding locations - * @since 2.6.0 - */ - protected void loadConfiguration(String location, @Nullable LogFile logFile, List overrides) { + private void reconfigure(String location, List overrides) { Assert.notNull(location, "'location' must not be null"); try { List configurations = new ArrayList<>(); - LoggerContext context = getLoggerContext(); - ResourceLoader resourceLoader = ApplicationResourceLoader.get(); - configurations.add(load(resourceLoader.getResource(location), context)); + ResourceLoader resourceLoader = ApplicationResourceLoader.get(getClassLoader()); + configurations.add(load(resourceLoader, location)); for (String override : overrides) { - Configuration overrideConfiguration = loadOverride(resourceLoader, override, context); + Configuration overrideConfiguration = loadOverride(resourceLoader, override); if (overrideConfiguration != null) { configurations.add(overrideConfiguration); } } - context.start(mergeConfigurations(configurations)); + this.loggerContext.reconfigure(mergeConfigurations(configurations)); } catch (Exception ex) { - throw new IllegalStateException("Could not initialize Log4J2 logging from " + location, ex); + String message = "Could not initialize Log4J2 logging from " + location; + if (!overrides.isEmpty()) { + message += " with overrides " + overrides; + } + throw new IllegalStateException(message, ex); } } - private Configuration load(Resource resource, LoggerContext context) throws IOException { + private Configuration load(ResourceLoader resourceLoader, String location) throws IOException { ConfigurationFactory factory = ConfigurationFactory.getInstance(); - if (resource.isFile()) { - try (InputStream inputStream = resource.getInputStream()) { - return factory.getConfiguration(context, new ConfigurationSource(inputStream, resource.getFile())); - } - } - URL url = resource.getURL(); - AuthorizationProvider authorizationProvider = ConfigurationFactory - .authorizationProvider(PropertiesUtil.getProperties()); - SslConfiguration sslConfiguration = url.getProtocol().equals("https") - ? SslConfigurationFactory.getSslConfiguration() : null; - URLConnection connection = UrlConnectionFactory.createConnection(url, 0, sslConfiguration, - authorizationProvider); - try (InputStream inputStream = connection.getInputStream()) { - return factory.getConfiguration(context, - new ConfigurationSource(inputStream, url, connection.getLastModified())); + Resource resource = resourceLoader.getResource(location); + Configuration configuration = factory.getConfiguration(getLoggerContext(), null, resource.getURI(), + getClassLoader()); + // The error handling in Log4j Core 2.25.x is not consistent: + // some loading and parsing errors result in a null configuration, + // others in an exception. + if (configuration == null) { + throw new ConfigurationException("Could not load Log4j Core configuration from " + location); } + return configuration; } - private @Nullable Configuration loadOverride(ResourceLoader resourceLoader, String location, LoggerContext context) - throws IOException { + private @Nullable Configuration loadOverride(ResourceLoader resourceLoader, String location) throws IOException { if (location.startsWith(OPTIONAL_PREFIX)) { - Resource resource = resourceLoader.getResource(location.substring(OPTIONAL_PREFIX.length())); + String actualLocation = location.substring(OPTIONAL_PREFIX.length()); + Resource resource = resourceLoader.getResource(actualLocation); try { - return (resource.exists()) ? load(resource, context) : null; + return (resource.exists()) ? load(resourceLoader, actualLocation) : null; } - catch (FileNotFoundException ex) { + catch (ConfigurationException | IOException ex) { + STATUS_LOGGER.debug("Could not load optional Log4j2 override from {}", actualLocation, ex); return null; } } - return load(resourceLoader.getResource(location), context); + return load(resourceLoader, location); } private Configuration mergeConfigurations(List configurations) { @@ -417,33 +361,11 @@ private Configuration mergeConfigurations(List configurations) { @Override protected void reinitialize(LoggingInitializationContext initializationContext) { - List overrides = getOverrides(initializationContext); - if (!CollectionUtils.isEmpty(overrides)) { - reinitializeWithOverrides(overrides); - } - else { - LoggerContext context = getLoggerContext(); - context.reconfigure(); - } - } - - private void reinitializeWithOverrides(List overrides) { - LoggerContext context = getLoggerContext(); - List configurations = new ArrayList<>(); - configurations.add(context.getConfiguration()); - ResourceLoader resourceLoader = ApplicationResourceLoader.get(); - for (String override : overrides) { - try { - Configuration overrideConfiguration = loadOverride(resourceLoader, override, context); - if (overrideConfiguration != null) { - configurations.add(overrideConfiguration); - } - } - catch (IOException ex) { - throw new RuntimeException("Failed to load overriding configuration from '" + override + "'", ex); - } - } - context.reconfigure(mergeConfigurations(configurations)); + String currentLocation = getSelfInitializationConfig(); + // `reinitialize` is only triggered when `getSelfInitializationConfig` returns a + // non-null value + Assert.notNull(currentLocation, "'currentLocation' must not be null"); + load(initializationContext, currentLocation, null); } @Override @@ -584,8 +506,8 @@ public void cleanUp() { return configuration.getLoggers().get(name); } - private LoggerContext getLoggerContext() { - return (LoggerContext) LogManager.getContext(false); + LoggerContext getLoggerContext() { + return this.loggerContext; } private boolean isAlreadyInitialized(LoggerContext loggerContext) { @@ -630,7 +552,12 @@ public static class Factory implements LoggingSystemFactory { @Override public @Nullable LoggingSystem getLoggingSystem(ClassLoader classLoader) { if (PRESENT) { - return new Log4J2LoggingSystem(classLoader); + try { + return createLoggingSystem(classLoader); + } + catch (IllegalStateException ex) { + // Log4j Core is not the active Log4j API provider + } } return null; } diff --git a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2RuntimeHints.java b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2RuntimeHints.java index 05fdf00326a6..135730795994 100644 --- a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2RuntimeHints.java +++ b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2RuntimeHints.java @@ -44,13 +44,6 @@ private void registerLog4j2Hints(RuntimeHints hints, @Nullable ClassLoader class hints.resources().registerPattern("org/springframework/boot/logging/log4j2/log4j2-file.xml"); hints.resources().registerPattern("log4j2.springboot"); // Declares the types that Log4j2LoggingSystem checks for existence reflectively. - hints.reflection().registerTypeIfPresent(classLoader, Log4J2LoggingSystem.JSON_TREE_PARSER_V2); - hints.reflection().registerTypeIfPresent(classLoader, Log4J2LoggingSystem.JSON_TREE_PARSER_V3); - hints.reflection().registerTypeIfPresent(classLoader, Log4J2LoggingSystem.PROPS_CONFIGURATION_FACTORY_V2); - hints.reflection().registerTypeIfPresent(classLoader, Log4J2LoggingSystem.PROPS_CONFIGURATION_FACTORY_V3); - hints.reflection().registerTypeIfPresent(classLoader, Log4J2LoggingSystem.YAML_TREE_PARSER_V2); - hints.reflection().registerTypeIfPresent(classLoader, Log4J2LoggingSystem.YAML_CONFIGURATION_FACTORY_V2); - hints.reflection().registerTypeIfPresent(classLoader, Log4J2LoggingSystem.YAML_CONFIGURATION_FACTORY_V3); hints.reflection().registerTypeIfPresent(classLoader, Log4J2LoggingSystem.LOG4J_BRIDGE_HANDLER); hints.reflection().registerTypeIfPresent(classLoader, Log4J2LoggingSystem.LOG4J_LOG_MANAGER); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java index f9e95fdd4f0c..72d960b7af85 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java @@ -23,16 +23,12 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.net.ProtocolException; -import java.util.ArrayList; -import java.util.Collections; import java.util.EnumSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.logging.Handler; import java.util.logging.Level; -import java.util.stream.Stream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -41,14 +37,9 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.LoggerConfig; -import org.apache.logging.log4j.core.config.Reconfigurable; import org.apache.logging.log4j.core.config.composite.CompositeConfiguration; -import org.apache.logging.log4j.core.config.json.JsonConfigurationFactory; import org.apache.logging.log4j.core.config.plugins.util.PluginRegistry; -import org.apache.logging.log4j.core.config.properties.PropertiesConfigurationBuilder; -import org.apache.logging.log4j.core.config.properties.PropertiesConfigurationFactory; import org.apache.logging.log4j.core.config.xml.XmlConfiguration; -import org.apache.logging.log4j.core.config.yaml.YamlConfigurationFactory; import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry; import org.apache.logging.log4j.jul.Log4jBridgeHandler; import org.apache.logging.log4j.status.StatusListener; @@ -58,10 +49,8 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; import org.slf4j.MDC; import org.springframework.boot.logging.AbstractLoggingSystemTests; @@ -113,29 +102,18 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests { private Logger logger; - private Configuration configuration; - - private String contextName; - @BeforeEach - void setup() { + void setup(TestInfo testInfo) { PluginRegistry.getInstance().clear(); - this.loggingSystem = new TestLog4J2LoggingSystem(); + this.loggingSystem = new TestLog4J2LoggingSystem(testInfo.getDisplayName()); this.environment = new MockEnvironment(); this.initializationContext = new LoggingInitializationContext(this.environment); - LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); - this.configuration = loggerContext.getConfiguration(); - this.loggingSystem.cleanUp(); - this.logger = LogManager.getLogger(getClass()); - this.contextName = loggerContext.getName(); + this.logger = this.loggingSystem.getLoggerContext().getLogger(getClass().getName()); } @AfterEach void cleanUp() { this.loggingSystem.cleanUp(); - LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); - loggerContext.stop(); - loggerContext.start(((Reconfigurable) this.configuration).reconfigure()); PluginRegistry.getInstance().clear(); } @@ -185,6 +163,17 @@ void testNonexistentConfigLocation() { "classpath:log4j2-nonexistent.xml", null)); } + @Test + @WithSpringXmlResource + void testSpringBootConfigLocation() { + this.loggingSystem.disableSelfInitialization(); + this.loggingSystem.beforeInitialize(); + this.loggingSystem.initialize(this.initializationContext, null, null); + Configuration configuration = this.loggingSystem.getConfiguration(); + assertThat(configuration.getName()).isEqualTo("SpringBoot"); + assertThat(configuration.getConfigurationSource().getLocation()).endsWith("log4j2-test-spring.xml"); + } + @Test void getSupportedLevels() { assertThat(this.loggingSystem.getSupportedLogLevels()).isEqualTo(EnumSet.allOf(LogLevel.class)); @@ -224,7 +213,8 @@ void getLoggerConfigurations() { @Test void getLoggerConfigurationsShouldReturnAllLoggers() { - LogManager.getLogger("org.springframework.boot.logging.log4j2.Log4J2LoggingSystemTests$Nested"); + this.loggingSystem.getLoggerContext() + .getLogger("org.springframework.boot.logging.log4j2.Log4J2LoggingSystemTests$Nested"); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); this.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG); @@ -243,7 +233,7 @@ void getLoggerConfigurationsShouldReturnAllLoggers() { void getLoggerConfigurationWhenHasCustomLevel() { this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); - LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); + LoggerContext loggerContext = this.loggingSystem.getLoggerContext(); String loggerName = getClass().getName(); org.apache.logging.log4j.Level level = org.apache.logging.log4j.Level.forName("CUSTOM_LEVEL", 1000); loggerContext.getConfiguration().addLogger(loggerName, new LoggerConfig(loggerName, level, true)); @@ -307,82 +297,6 @@ void loggingThatUsesJulIsCaptured(CapturedOutput output) { assertThat(output).contains("Hello world"); } - static Stream configLocationsWithConfigurationFileSystemProperty() { - return Stream.of("log4j2.configurationFile", "log4j.configuration.location"); - } - - @ParameterizedTest - @MethodSource - void configLocationsWithConfigurationFileSystemProperty(String propertyName) { - System.setProperty(propertyName, "custom-log4j2.properties"); - try { - assertThat(this.loggingSystem.getStandardConfigLocations()).containsExactly("custom-log4j2.properties", - "log4j2-test" + this.contextName + ".xml", "log4j2-test.xml", "log4j2" + this.contextName + ".xml", - "log4j2.xml"); - } - finally { - System.clearProperty(propertyName); - } - } - - static Stream standardConfigLocations() { - // For each configuration file format we make "available" to the - // Log4j2LoggingSystem: - // - The Log4j Core `ConfigurationFactory` class - // - The tree parser used internally by that configuration factory - return Stream.of( - // No classes, only XML - Arguments.of(Collections.emptyList(), List.of(".xml")), - // Log4j Core 2 - Arguments.of(List.of(JsonConfigurationFactory.class.getName(), - "com.fasterxml.jackson.databind.ObjectMapper"), List.of(".json", ".jsn", ".xml")), - Arguments.of(List.of(PropertiesConfigurationFactory.class.getName(), - PropertiesConfigurationBuilder.class.getName()), List.of(".properties", ".xml")), - Arguments.of(List.of(YamlConfigurationFactory.class.getName(), - "com.fasterxml.jackson.dataformat.yaml.YAMLMapper"), List.of(".yaml", ".yml", ".xml")), - Arguments.of(List.of(JsonConfigurationFactory.class.getName(), - "com.fasterxml.jackson.databind.ObjectMapper", PropertiesConfigurationFactory.class.getName(), - PropertiesConfigurationBuilder.class.getName(), YamlConfigurationFactory.class.getName(), - "com.fasterxml.jackson.dataformat.yaml.YAMLMapper"), - List.of(".properties", ".yaml", ".yml", ".json", ".jsn", ".xml")), - // Log4j Core 3 - Arguments.of(List.of(JsonConfigurationFactory.class.getName(), - "org.apache.logging.log4j.kit.json.JsonReader"), List.of(".json", ".jsn", ".xml")), - Arguments.of(List.of("org.apache.logging.log4j.config.properties.JavaPropsConfigurationFactory", - "tools.jackson.dataformat.javaprop.JavaPropsMapper"), List.of(".properties", ".xml")), - Arguments.of(List.of("org.apache.logging.log4j.config.yaml.YamlConfigurationFactory", - "tools.jackson.dataformat.yaml.YAMLMapper"), List.of(".yaml", ".yml", ".xml")), - Arguments.of( - List.of(JsonConfigurationFactory.class.getName(), - "org.apache.logging.log4j.kit.json.JsonReader", - "org.apache.logging.log4j.config.properties.JavaPropsConfigurationFactory", - "tools.jackson.dataformat.javaprop.JavaPropsMapper", - "org.apache.logging.log4j.config.yaml.YamlConfigurationFactory", - "tools.jackson.dataformat.yaml.YAMLMapper"), - List.of(".properties", ".yaml", ".yml", ".json", ".jsn", ".xml"))); - } - - @ParameterizedTest - @MethodSource - void standardConfigLocations(List availableClasses, List expectedSuffixes) { - this.loggingSystem.availableClasses(availableClasses.toArray(new String[0])); - String[] locations = this.loggingSystem.getStandardConfigLocations(); - assertThat(locations).hasSize(4 * expectedSuffixes.size()); - List expected = new ArrayList<>(); - expectedSuffixes.forEach((s) -> expected.add("log4j2-test" + this.contextName + s)); - expectedSuffixes.forEach((s) -> expected.add("log4j2-test" + s)); - expectedSuffixes.forEach((s) -> expected.add("log4j2" + this.contextName + s)); - expectedSuffixes.forEach((s) -> expected.add("log4j2" + s)); - assertThat(locations).containsExactlyElementsOf(expected); - } - - @Test - void springConfigLocations() { - String[] locations = getSpringConfigLocations(this.loggingSystem); - assertThat(locations).containsExactly("log4j2-test" + this.contextName + "-spring.xml", - "log4j2-test-spring.xml", "log4j2" + this.contextName + "-spring.xml", "log4j2-spring.xml"); - } - @Test void exceptionsIncludeClassPackaging(CapturedOutput output) { this.loggingSystem.beforeInitialize(); @@ -421,7 +335,7 @@ void customExceptionConversionWord(CapturedOutput output) { @Test void initializationIsOnlyPerformedOnceUntilCleanedUp() { - LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); + LoggerContext loggerContext = this.loggingSystem.getLoggerContext(); PropertyChangeListener listener = mock(PropertyChangeListener.class); loggerContext.addPropertyChangeListener(listener); this.loggingSystem.beforeInitialize(); @@ -453,7 +367,7 @@ void getLoggerConfigurationWithResetLevelReturnsNull() { @Test void getLoggerConfigurationWithResetLevelWhenAlreadyConfiguredReturnsParentConfiguredLevel() { - LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); + LoggerContext loggerContext = this.loggingSystem.getLoggerContext(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); loggerContext.getConfiguration() @@ -472,18 +386,21 @@ void getLoggerConfigurationWithResetLevelWhenAlreadyConfiguredReturnsParentConfi @Test void log4jLevelsArePropagatedToJul() { - this.loggingSystem.beforeInitialize(); + // In this test we need to use the global logging system, since JUL is a global + // singleton. + LoggingSystem loggingSystem = LoggingSystem.get(getClass().getClassLoader()); + loggingSystem.beforeInitialize(); java.util.logging.Logger rootLogger = java.util.logging.Logger.getLogger(""); // check if Log4jBridgeHandler is used Handler[] handlers = rootLogger.getHandlers(); assertThat(handlers).hasSize(1); assertThat(handlers[0]).isInstanceOf(Log4jBridgeHandler.class); - this.loggingSystem.initialize(this.initializationContext, null, null); + loggingSystem.initialize(this.initializationContext, null, null); java.util.logging.Logger logger = java.util.logging.Logger.getLogger(Log4J2LoggingSystemTests.class.getName()); logger.info("Log to trigger level propagation"); assertThat(logger.getLevel()).isNull(); - this.loggingSystem.setLogLevel(Log4J2LoggingSystemTests.class.getName(), LogLevel.DEBUG); + loggingSystem.setLogLevel(Log4J2LoggingSystemTests.class.getName(), LogLevel.DEBUG); assertThat(logger.getLevel()).isEqualTo(Level.FINE); } @@ -557,7 +474,7 @@ void compositeConfigurationWithStandardConfigLocationConfiguration() { void initializeAttachesEnvironmentToLoggerContext() { this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); - LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); + LoggerContext loggerContext = this.loggingSystem.getLoggerContext(); Environment environment = Log4J2LoggingSystem.getEnvironment(loggerContext); assertThat(environment).isSameAs(this.environment); } @@ -566,7 +483,7 @@ void initializeAttachesEnvironmentToLoggerContext() { void initializeRegisterStatusListenerAndAttachToLoggerContext() { this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); - LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); + LoggerContext loggerContext = this.loggingSystem.getLoggerContext(); StatusListener statusListener = (StatusListener) loggerContext .getObject(Log4J2LoggingSystem.STATUS_LISTENER_KEY); assertThat(statusListener).isNotNull(); @@ -578,7 +495,7 @@ void statusListenerIsUpdatedUponReinitialization() { this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); // listener should be registered - LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); + LoggerContext loggerContext = this.loggingSystem.getLoggerContext(); StatusListener statusListener = (StatusListener) loggerContext .getObject(Log4J2LoggingSystem.STATUS_LISTENER_KEY); assertThat(statusListener).isNotNull(); @@ -621,24 +538,13 @@ void environmentIsUpdatedUponReinitialization() { assertThat(PropertiesUtil.getProperties().getStringProperty("spring")).isEqualTo("boot: two"); } - @Test - void nonFileUrlsAreResolvedUsingLog4J2UrlConnectionFactory() { - this.loggingSystem.beforeInitialize(); - assertThatIllegalStateException() - .isThrownBy(() -> this.loggingSystem.initialize(this.initializationContext, - "http://localhost:8080/shouldnotwork", null)) - .havingCause() - .isInstanceOf(ProtocolException.class) - .withMessageContaining("http has not been enabled"); - } - @Test void correlationLoggingToFileWhenExpectCorrelationIdTrueAndMdcContent() { this.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, "true"); new LoggingSystemProperties(this.environment).apply(); File file = new File(tmpDir(), "log4j2-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, logFile); MDC.setContextMap(Map.of("traceId", "01234567890123456789012345678901", "spanId", "0123456789012345")); @@ -650,7 +556,7 @@ void correlationLoggingToFileWhenExpectCorrelationIdTrueAndMdcContent() { @Test void correlationLoggingToConsoleWhenExpectCorrelationIdTrueAndMdcContent(CapturedOutput output) { this.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, "true"); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); MDC.setContextMap(Map.of("traceId", "01234567890123456789012345678901", "spanId", "0123456789012345")); @@ -662,7 +568,7 @@ void correlationLoggingToConsoleWhenExpectCorrelationIdTrueAndMdcContent(Capture @Test void correlationLoggingToConsoleWhenExpectCorrelationIdFalseAndMdcContent(CapturedOutput output) { this.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, "false"); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); MDC.setContextMap(Map.of("traceId", "01234567890123456789012345678901", "spanId", "0123456789012345")); @@ -673,7 +579,7 @@ void correlationLoggingToConsoleWhenExpectCorrelationIdFalseAndMdcContent(Captur @Test void correlationLoggingToConsoleWhenExpectCorrelationIdTrueAndNoMdcContent(CapturedOutput output) { this.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, "true"); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); this.logger.info("Hello world"); @@ -684,7 +590,7 @@ void correlationLoggingToConsoleWhenExpectCorrelationIdTrueAndNoMdcContent(Captu @Test void correlationLoggingToConsoleWhenHasCorrelationPattern(CapturedOutput output) { this.environment.setProperty("logging.pattern.correlation", "%correlationId{spanId(0),traceId(0)}"); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); MDC.setContextMap(Map.of("traceId", "01234567890123456789012345678901", "spanId", "0123456789012345")); @@ -696,7 +602,7 @@ void correlationLoggingToConsoleWhenHasCorrelationPattern(CapturedOutput output) @Test void applicationNameLoggingToConsoleWhenHasApplicationName(CapturedOutput output) { this.environment.setProperty("spring.application.name", "myapp"); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); this.logger.info("Hello world"); @@ -706,7 +612,7 @@ void applicationNameLoggingToConsoleWhenHasApplicationName(CapturedOutput output @Test void applicationNameLoggingToConsoleWhenHasApplicationNameWithParenthesis(CapturedOutput output) { this.environment.setProperty("spring.application.name", "myapp (dev)"); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); this.logger.info("Hello world"); @@ -717,7 +623,7 @@ void applicationNameLoggingToConsoleWhenHasApplicationNameWithParenthesis(Captur void applicationNameLoggingToConsoleWhenDisabled(CapturedOutput output) { this.environment.setProperty("spring.application.name", "myapp"); this.environment.setProperty("logging.include-application-name", "false"); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); this.logger.info("Hello world"); @@ -732,7 +638,7 @@ void applicationNameLoggingToFileWhenHasApplicationName() { new LoggingSystemProperties(this.environment).apply(); File file = new File(tmpDir(), "log4j2-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, logFile); this.logger.info("Hello world"); @@ -745,7 +651,7 @@ void applicationNameLoggingToFileWhenHasApplicationNameWithParenthesis() { new LoggingSystemProperties(this.environment).apply(); File file = new File(tmpDir(), "log4j2-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, logFile); this.logger.info("Hello world"); @@ -759,7 +665,7 @@ void applicationNameLoggingToFileWhenDisabled() { new LoggingSystemProperties(this.environment).apply(); File file = new File(tmpDir(), "log4j2-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, logFile); this.logger.info("Hello world"); @@ -771,7 +677,7 @@ void applicationNameLoggingToFileWhenDisabled() { @Test void applicationGroupLoggingToConsoleWhenHasApplicationGroup(CapturedOutput output) { this.environment.setProperty("spring.application.group", "mygroup"); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); this.logger.info("Hello world"); @@ -781,7 +687,7 @@ void applicationGroupLoggingToConsoleWhenHasApplicationGroup(CapturedOutput outp @Test void applicationGroupLoggingToConsoleWhenHasApplicationGroupWithParenthesis(CapturedOutput output) { this.environment.setProperty("spring.application.group", "mygroup (dev)"); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); this.logger.info("Hello world"); @@ -792,7 +698,7 @@ void applicationGroupLoggingToConsoleWhenHasApplicationGroupWithParenthesis(Capt void applicationGroupLoggingToConsoleWhenDisabled(CapturedOutput output) { this.environment.setProperty("spring.application.group", "mygroup"); this.environment.setProperty("logging.include-application-group", "false"); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, null); this.logger.info("Hello world"); @@ -806,7 +712,7 @@ void applicationGroupLoggingToFileWhenHasApplicationGroup() { new LoggingSystemProperties(this.environment).apply(); File file = new File(tmpDir(), "log4j2-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, logFile); this.logger.info("Hello world"); @@ -819,7 +725,7 @@ void applicationGroupLoggingToFileWhenHasApplicationGroupWithParenthesis() { new LoggingSystemProperties(this.environment).apply(); File file = new File(tmpDir(), "log4j2-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, logFile); this.logger.info("Hello world"); @@ -833,7 +739,7 @@ void applicationGroupLoggingToFileWhenDisabled() { new LoggingSystemProperties(this.environment).apply(); File file = new File(tmpDir(), "log4j2-test.log"); LogFile logFile = getLogFile(file.getPath(), null); - this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.disableSelfInitialization(); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(this.initializationContext, null, logFile); this.logger.info("Hello world"); @@ -909,4 +815,27 @@ static class Nested { } + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + @WithResource(name = "log4j2-test-spring.xml", + content = """ + + + + + + + + + + + + """) + private @interface WithSpringXmlResource { + + } + } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2RuntimeHintsTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2RuntimeHintsTests.java index c2389a26c993..517b3b679303 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2RuntimeHintsTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2RuntimeHintsTests.java @@ -20,8 +20,6 @@ import java.net.URLClassLoader; import java.util.Arrays; -import org.apache.logging.log4j.core.config.properties.PropertiesConfigurationFactory; -import org.apache.logging.log4j.core.config.yaml.YamlConfigurationFactory; import org.apache.logging.log4j.core.impl.Log4jContextFactory; import org.apache.logging.log4j.jul.Log4jBridgeHandler; import org.apache.logging.log4j.jul.LogManager; @@ -52,8 +50,6 @@ void registersHintsForTypesCheckedByLog4J2LoggingSystem() { assertThat(reflectionHints.onType(Log4jContextFactory.class)).accepts(runtimeHints); assertThat(reflectionHints.onType(Log4jBridgeHandler.class)).accepts(runtimeHints); assertThat(reflectionHints.onType(LogManager.class)).accepts(runtimeHints); - assertThat(reflectionHints.onType(PropertiesConfigurationFactory.class)).accepts(runtimeHints); - assertThat(reflectionHints.onType(YamlConfigurationFactory.class)).accepts(runtimeHints); } @Test @@ -63,6 +59,7 @@ void registersHintsForLog4j2DefaultConfigurationFiles() { .accepts(runtimeHints); assertThat(resourceHints.forResource("org/springframework/boot/logging/log4j2/log4j2-file.xml")) .accepts(runtimeHints); + assertThat(resourceHints.forResource("log4j2.springboot")).accepts(runtimeHints); } @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringProfileArbiterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringProfileArbiterTests.java index c7a4a8ea5a1d..90b0a6f4c3fb 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringProfileArbiterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringProfileArbiterTests.java @@ -22,16 +22,13 @@ import java.lang.annotation.Target; import java.util.Set; -import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.config.Reconfigurable; import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.PropertySource; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.logging.LoggingInitializationContext; @@ -57,7 +54,7 @@ class SpringProfileArbiterTests { private CapturedOutput output; - private final TestLog4J2LoggingSystem loggingSystem = new TestLog4J2LoggingSystem(); + private TestLog4J2LoggingSystem loggingSystem; private final MockEnvironment environment = new MockEnvironment(); @@ -66,24 +63,17 @@ class SpringProfileArbiterTests { private Logger logger; - private Configuration configuration; - @BeforeEach - void setup(CapturedOutput output) { + void setup(CapturedOutput output, TestInfo testInfo) { this.output = output; - LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); - this.configuration = loggerContext.getConfiguration(); - this.loggingSystem.cleanUp(); - this.logger = LogManager.getLogger(getClass()); + this.loggingSystem = new TestLog4J2LoggingSystem(testInfo.getDisplayName()); + this.logger = this.loggingSystem.getLoggerContext().getLogger(getClass().getName()); cleanUpPropertySources(); } @AfterEach void cleanUp() { this.loggingSystem.cleanUp(); - LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); - loggerContext.stop(); - loggerContext.start(((Reconfigurable) this.configuration).reconfigure()); cleanUpPropertySources(); } @@ -170,11 +160,11 @@ private void initialize(String config) { @WithResource(name = "multi-profile-names.xml", content = """ - - + + - - + + """) private @interface WithMultiProfileNamesXmlResource { @@ -186,11 +176,11 @@ private void initialize(String config) { @WithResource(name = "profile-expression.xml", content = """ - - + + - - + + """) private @interface WithProfileExpressionXmlResource { @@ -202,11 +192,11 @@ private void initialize(String config) { @WithResource(name = "production-profile.xml", content = """ - - + + - - + + """) private @interface WithProductionProfileXmlResource { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/TestLog4J2LoggingSystem.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/TestLog4J2LoggingSystem.java index c7de85ea630e..1f3a5598d3bf 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/TestLog4J2LoggingSystem.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/TestLog4J2LoggingSystem.java @@ -16,54 +16,31 @@ package org.springframework.boot.logging.log4j2; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; import org.jspecify.annotations.Nullable; class TestLog4J2LoggingSystem extends Log4J2LoggingSystem { - private final List availableClasses = new ArrayList<>(); - - private String @Nullable [] standardConfigLocations; + private boolean disableSelfInitialization = false; - TestLog4J2LoggingSystem() { - super(TestLog4J2LoggingSystem.class.getClassLoader()); + TestLog4J2LoggingSystem(String contextName) { + // Tests add resources to the thread context classloader + super(Thread.currentThread().getContextClassLoader(), new LoggerContext(contextName)); + getLoggerContext().start(); } Configuration getConfiguration() { return getLoggerContext().getConfiguration(); } - private LoggerContext getLoggerContext() { - return (LoggerContext) LogManager.getContext(false); - } - @Override - protected boolean isClassAvailable(ClassLoader classLoader, String className) { - return this.availableClasses.contains(className); - } - - void availableClasses(String... classNames) { - Collections.addAll(this.availableClasses, classNames); - } - - @Override - protected String[] getStandardConfigLocations() { - return (this.standardConfigLocations != null) ? this.standardConfigLocations - : super.getStandardConfigLocations(); - } - - void setStandardConfigLocations(boolean standardConfigLocations) { - this.standardConfigLocations = (!standardConfigLocations) ? new String[0] : null; + protected @Nullable String getSelfInitializationConfig() { + return this.disableSelfInitialization ? null : super.getSelfInitializationConfig(); } - void setStandardConfigLocations(String[] standardConfigLocations) { - this.standardConfigLocations = standardConfigLocations; + void disableSelfInitialization() { + this.disableSelfInitialization = true; } }