Introduce configurable refresh support in SmartContextLoader SPI
Prior to this commit, the contract of the loadContext() method in the SmartContextLoader SPI required that the ApplicationContext be returned in a fully refreshed state with a JVM shutdown hook registered for it. However, in order to support AOT processing within the Spring TestContext Framework (TCF), we need a way to signal to SmartContextLoader implementations that they should load the test's ApplicationContext without refreshing it or registering a JVM shutdown hook. To address this issue, this commit: - Introduces a new loadContext(MergedContextConfiguration, boolean) method. The boolean `refresh` flag controls whether the returned ApplicationContext should be refreshed and have a JVM shutdown hook registered for it. - Deprecates the existing loadContext(MergedContextConfiguration) method in favor of loadContext(MergedContextConfiguration, boolean). - Removes all use of the deprecated method within the spring-test module, excluding the exception mentioned below. Note that loadContext(MergedContextConfiguration, boolean) is implemented as an interface `default` method which delegates to the deprecated loadContext(MergedContextConfiguration) method for backward compatibility. When migrating a SmartContextLoader to Spring Framework 6.0, implementations that directly implement the SmartContextLoader SPI (instead of extending AbstractGenericContextLoader or AbstractGenericWebContextLoader) will need to override the new loadContext(MergedContextConfiguration, boolean) method in order to honor the `refresh` flag for AOT processing support. See the implementation in AbstractGenericContextLoader for an example of how this can be achieved. Closes gh-28906
This commit is contained in:
parent
dcad3beeb9
commit
903e9f2a02
|
@ -62,7 +62,7 @@ import org.springframework.util.StringUtils;
|
||||||
* @see ActiveProfiles
|
* @see ActiveProfiles
|
||||||
* @see TestPropertySource
|
* @see TestPropertySource
|
||||||
* @see ContextConfigurationAttributes
|
* @see ContextConfigurationAttributes
|
||||||
* @see SmartContextLoader#loadContext(MergedContextConfiguration)
|
* @see SmartContextLoader#loadContext(MergedContextConfiguration, boolean)
|
||||||
*/
|
*/
|
||||||
public class MergedContextConfiguration implements Serializable {
|
public class MergedContextConfiguration implements Serializable {
|
||||||
|
|
||||||
|
|
|
@ -25,34 +25,34 @@ import org.springframework.lang.Nullable;
|
||||||
*
|
*
|
||||||
* <p>The {@code SmartContextLoader} SPI supersedes the {@link ContextLoader} SPI
|
* <p>The {@code SmartContextLoader} SPI supersedes the {@link ContextLoader} SPI
|
||||||
* introduced in Spring 2.5: a {@code SmartContextLoader} can choose to process
|
* introduced in Spring 2.5: a {@code SmartContextLoader} can choose to process
|
||||||
* resource locations, annotated classes, or a combination of both. Furthermore, a
|
* resource locations, component classes, or a combination of both. Furthermore, a
|
||||||
* {@code SmartContextLoader} can configure the context that it
|
* {@code SmartContextLoader} can configure the context that it
|
||||||
* {@linkplain #loadContext(MergedContextConfiguration) loads} based on any
|
* {@linkplain #loadContext(MergedContextConfiguration, boolean) loads} based on
|
||||||
* properties available in the provided {@link MergedContextConfiguration}. For
|
* any properties available in the provided {@link MergedContextConfiguration}.
|
||||||
* example, active bean definition profiles can be configured for the context
|
* For example, active bean definition profiles can be configured for the context
|
||||||
* based on {@link MergedContextConfiguration#getActiveProfiles()}.
|
* based on {@link MergedContextConfiguration#getActiveProfiles()}.
|
||||||
*
|
*
|
||||||
* <p>See the Javadoc for {@link ContextConfiguration @ContextConfiguration}
|
* <p>See the Javadoc for {@link ContextConfiguration @ContextConfiguration}
|
||||||
* for a definition of <em>annotated class</em>.
|
* for a definition of <em>component classes</em>.
|
||||||
*
|
*
|
||||||
* <p>Clients of a {@code SmartContextLoader} should call
|
* <p>Clients of a {@code SmartContextLoader} should call
|
||||||
* {@link #processContextConfiguration(ContextConfigurationAttributes)
|
* {@link #processContextConfiguration(ContextConfigurationAttributes)
|
||||||
* processContextConfiguration()} prior to calling
|
* processContextConfiguration()} prior to calling
|
||||||
* {@link #loadContext(MergedContextConfiguration) loadContext()}. This gives a
|
* {@link #loadContext(MergedContextConfiguration, boolean) loadContext()}. This
|
||||||
* {@code SmartContextLoader} the opportunity to provide custom support for
|
* gives a {@code SmartContextLoader} the opportunity to provide custom support
|
||||||
* modifying resource locations or detecting default resource locations or
|
* for modifying resource locations or detecting default resource locations or
|
||||||
* default configuration classes. The results of
|
* default configuration classes. The results of
|
||||||
* {@link #processContextConfiguration(ContextConfigurationAttributes)
|
* {@link #processContextConfiguration(ContextConfigurationAttributes)
|
||||||
* processContextConfiguration()} should be merged for all classes in the
|
* processContextConfiguration()} should be merged for all classes in the
|
||||||
* hierarchy of the root test class and then supplied to
|
* hierarchy of the root test class and then supplied to
|
||||||
* {@link #loadContext(MergedContextConfiguration) loadContext()}.
|
* {@link #loadContext(MergedContextConfiguration, boolean) loadContext()}.
|
||||||
*
|
*
|
||||||
* <p>NOTE: As of Spring Framework 6.0, {@code SmartContextLoader} no longer
|
* <p>NOTE: As of Spring Framework 6.0, {@code SmartContextLoader} no longer
|
||||||
* supports methods defined in the {@code ContextLoader} SPI.
|
* supports methods defined in the {@code ContextLoader} SPI.
|
||||||
*
|
*
|
||||||
* <p>Concrete implementations must provide a {@code public} no-args constructor.
|
* <p>Concrete implementations must provide a {@code public} no-args constructor.
|
||||||
*
|
*
|
||||||
* <p>Spring provides the following out-of-the-box implementations:
|
* <p>Spring provides the following {@code SmartContextLoader} implementations.
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link org.springframework.test.context.support.DelegatingSmartContextLoader DelegatingSmartContextLoader}</li>
|
* <li>{@link org.springframework.test.context.support.DelegatingSmartContextLoader DelegatingSmartContextLoader}</li>
|
||||||
* <li>{@link org.springframework.test.context.support.AnnotationConfigContextLoader AnnotationConfigContextLoader}</li>
|
* <li>{@link org.springframework.test.context.support.AnnotationConfigContextLoader AnnotationConfigContextLoader}</li>
|
||||||
|
@ -92,10 +92,9 @@ public interface SmartContextLoader extends ContextLoader {
|
||||||
void processContextConfiguration(ContextConfigurationAttributes configAttributes);
|
void processContextConfiguration(ContextConfigurationAttributes configAttributes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a new {@linkplain ApplicationContext context} based on the supplied
|
* Load a new {@link ApplicationContext} based on the supplied
|
||||||
* {@link MergedContextConfiguration merged context configuration},
|
* {@link MergedContextConfiguration}, configure the context, and return the
|
||||||
* configure the context, and return the context in a fully <em>refreshed</em>
|
* context in a fully <em>refreshed</em> state.
|
||||||
* state.
|
|
||||||
* <p>Concrete implementations should register annotation configuration
|
* <p>Concrete implementations should register annotation configuration
|
||||||
* processors with bean factories of
|
* processors with bean factories of
|
||||||
* {@link ApplicationContext application contexts} loaded by this
|
* {@link ApplicationContext application contexts} loaded by this
|
||||||
|
@ -134,9 +133,68 @@ public interface SmartContextLoader extends ContextLoader {
|
||||||
* @see #processContextConfiguration(ContextConfigurationAttributes)
|
* @see #processContextConfiguration(ContextConfigurationAttributes)
|
||||||
* @see org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
* @see org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
||||||
* @see org.springframework.context.ConfigurableApplicationContext#getEnvironment()
|
* @see org.springframework.context.ConfigurableApplicationContext#getEnvironment()
|
||||||
|
* @deprecated as of Spring Framework 6.0, in favor of {@link #loadContext(MergedContextConfiguration, boolean)}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception;
|
ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a new {@linkplain ApplicationContext} based on the supplied
|
||||||
|
* {@link MergedContextConfiguration}, configure the context, and return the
|
||||||
|
* context.
|
||||||
|
* <p>Concrete implementations should register annotation configuration
|
||||||
|
* processors with bean factories of
|
||||||
|
* {@linkplain ApplicationContext application contexts} loaded by this
|
||||||
|
* {@code SmartContextLoader}. Beans will therefore automatically be
|
||||||
|
* candidates for annotation-based dependency injection using
|
||||||
|
* {@link org.springframework.beans.factory.annotation.Autowired @Autowired},
|
||||||
|
* {@link jakarta.annotation.Resource @Resource}, and
|
||||||
|
* {@link jakarta.inject.Inject @Inject}. In addition, concrete implementations
|
||||||
|
* should perform the following actions.
|
||||||
|
* <ul>
|
||||||
|
* <li>Set the parent {@code ApplicationContext} if appropriate (see
|
||||||
|
* {@link MergedContextConfiguration#getParent()}).</li>
|
||||||
|
* <li>Set the active bean definition profiles in the context's
|
||||||
|
* {@link org.springframework.core.env.Environment Environment} (see
|
||||||
|
* {@link MergedContextConfiguration#getActiveProfiles()}).</li>
|
||||||
|
* <li>Add test {@link org.springframework.core.env.PropertySource PropertySources}
|
||||||
|
* to the {@code Environment} (see
|
||||||
|
* {@link MergedContextConfiguration#getPropertySourceLocations()},
|
||||||
|
* {@link MergedContextConfiguration#getPropertySourceProperties()}, and
|
||||||
|
* {@link org.springframework.test.context.support.TestPropertySourceUtils
|
||||||
|
* TestPropertySourceUtils}).</li>
|
||||||
|
* <li>Invoke {@link org.springframework.context.ApplicationContextInitializer
|
||||||
|
* ApplicationContextInitializers} (see
|
||||||
|
* {@link MergedContextConfiguration#getContextInitializerClasses()}).</li>
|
||||||
|
* <li>Invoke {@link ContextCustomizer ContextCustomizers} (see
|
||||||
|
* {@link MergedContextConfiguration#getContextCustomizers()}).</li>
|
||||||
|
* <li>If the supplied {@code refresh} flag is {@code true},
|
||||||
|
* {@linkplain org.springframework.context.ConfigurableApplicationContext#refresh()
|
||||||
|
* refresh} the {@code ApplicationContext} and
|
||||||
|
* {@linkplain org.springframework.context.ConfigurableApplicationContext#registerShutdownHook()
|
||||||
|
* register a JVM shutdown hook} for it.</li>
|
||||||
|
* </ul>
|
||||||
|
* <p>The default implementation delegates to {@link #loadContext(MergedContextConfiguration)}
|
||||||
|
* for backward compatibility. Concrete implementations should therefore
|
||||||
|
* override this method in order to honor the {@code refresh} flag which is
|
||||||
|
* required for AOT (ahead of time) processing support.
|
||||||
|
* @param mergedConfig the merged context configuration to use to load the
|
||||||
|
* application context
|
||||||
|
* @param refresh whether to refresh the {@code ApplicationContext} and register
|
||||||
|
* a JVM shutdown hook for it
|
||||||
|
* @return a new application context
|
||||||
|
* @throws Exception if context loading failed
|
||||||
|
* @since 6.0
|
||||||
|
* @see #processContextConfiguration(ContextConfigurationAttributes)
|
||||||
|
* @see org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
||||||
|
* @see org.springframework.context.ConfigurableApplicationContext#getEnvironment()
|
||||||
|
* @see org.springframework.context.ConfigurableApplicationContext#registerShutdownHook()
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
default ApplicationContext loadContext(MergedContextConfiguration mergedConfig, boolean refresh) throws Exception {
|
||||||
|
return loadContext(mergedConfig);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code SmartContextLoader} does not support deprecated {@link ContextLoader} methods.
|
* {@code SmartContextLoader} does not support deprecated {@link ContextLoader} methods.
|
||||||
* Call {@link #processContextConfiguration(ContextConfigurationAttributes)} instead.
|
* Call {@link #processContextConfiguration(ContextConfigurationAttributes)} instead.
|
||||||
|
@ -153,7 +211,7 @@ public interface SmartContextLoader extends ContextLoader {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code SmartContextLoader} does not support deprecated {@link ContextLoader} methods.
|
* {@code SmartContextLoader} does not support deprecated {@link ContextLoader} methods.
|
||||||
* <p>Call {@link #loadContext(MergedContextConfiguration)} instead.
|
* <p>Call {@link #loadContext(MergedContextConfiguration, boolean)} instead.
|
||||||
* @throws UnsupportedOperationException in this implementation
|
* @throws UnsupportedOperationException in this implementation
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
|
@ -162,7 +220,7 @@ public interface SmartContextLoader extends ContextLoader {
|
||||||
default ApplicationContext loadContext(String... locations) throws Exception {
|
default ApplicationContext loadContext(String... locations) throws Exception {
|
||||||
throw new UnsupportedOperationException("""
|
throw new UnsupportedOperationException("""
|
||||||
SmartContextLoader does not support the ContextLoader SPI. \
|
SmartContextLoader does not support the ContextLoader SPI. \
|
||||||
Call loadContext(MergedContextConfiguration) instead.""");
|
Call loadContext(MergedContextConfiguration, boolean) instead.""");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ public class DefaultCacheAwareContextLoaderDelegate implements CacheAwareContext
|
||||||
ApplicationContext applicationContext;
|
ApplicationContext applicationContext;
|
||||||
|
|
||||||
if (contextLoader instanceof SmartContextLoader smartContextLoader) {
|
if (contextLoader instanceof SmartContextLoader smartContextLoader) {
|
||||||
applicationContext = smartContextLoader.loadContext(mergedContextConfiguration);
|
applicationContext = smartContextLoader.loadContext(mergedContextConfiguration, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
String[] locations = mergedContextConfiguration.getLocations();
|
String[] locations = mergedContextConfiguration.getLocations();
|
||||||
|
|
|
@ -128,7 +128,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||||
* @see TestPropertySourceUtils#addPropertiesFilesToEnvironment
|
* @see TestPropertySourceUtils#addPropertiesFilesToEnvironment
|
||||||
* @see TestPropertySourceUtils#addInlinedPropertiesToEnvironment
|
* @see TestPropertySourceUtils#addInlinedPropertiesToEnvironment
|
||||||
* @see ApplicationContextInitializer#initialize(ConfigurableApplicationContext)
|
* @see ApplicationContextInitializer#initialize(ConfigurableApplicationContext)
|
||||||
* @see #loadContext(MergedContextConfiguration)
|
* @see #loadContext(MergedContextConfiguration, boolean)
|
||||||
* @see ConfigurableApplicationContext#setId
|
* @see ConfigurableApplicationContext#setId
|
||||||
*/
|
*/
|
||||||
protected void prepareContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
|
protected void prepareContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
|
||||||
|
|
|
@ -175,6 +175,18 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Although this method is officially deprecated, for backward compatibility
|
||||||
|
* it delegates to {@link #loadContext(MergedContextConfiguration, boolean)},
|
||||||
|
* supplying {@code true} for the {@code refresh} flag.
|
||||||
|
* @deprecated as of Spring Framework 6.0, in favor of {@link #loadContext(MergedContextConfiguration, boolean)}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
||||||
|
return loadContext(mergedConfig, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegates to an appropriate candidate {@code SmartContextLoader} to load
|
* Delegates to an appropriate candidate {@code SmartContextLoader} to load
|
||||||
* an {@link ApplicationContext}.
|
* an {@link ApplicationContext}.
|
||||||
|
@ -191,12 +203,16 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||||
* the annotation-based loader will load the {@code ApplicationContext}.</li>
|
* the annotation-based loader will load the {@code ApplicationContext}.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* @param mergedConfig the merged context configuration to use to load the application context
|
* @param mergedConfig the merged context configuration to use to load the application context
|
||||||
|
* @param refresh whether to refresh the {@code ApplicationContext} and register
|
||||||
|
* a JVM shutdown hook for it
|
||||||
|
* @return a new application context
|
||||||
* @throws IllegalArgumentException if the supplied merged configuration is {@code null}
|
* @throws IllegalArgumentException if the supplied merged configuration is {@code null}
|
||||||
* @throws IllegalStateException if neither candidate loader is capable of loading an
|
* @throws IllegalStateException if neither candidate loader is capable of loading an
|
||||||
* {@code ApplicationContext} from the supplied merged context configuration
|
* {@code ApplicationContext} from the supplied merged context configuration
|
||||||
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
public ApplicationContext loadContext(MergedContextConfiguration mergedConfig, boolean refresh) throws Exception {
|
||||||
Assert.notNull(mergedConfig, "MergedContextConfiguration must not be null");
|
Assert.notNull(mergedConfig, "MergedContextConfiguration must not be null");
|
||||||
|
|
||||||
Assert.state(!(mergedConfig.hasLocations() && mergedConfig.hasClasses()), () -> String.format(
|
Assert.state(!(mergedConfig.hasLocations() && mergedConfig.hasClasses()), () -> String.format(
|
||||||
|
@ -209,7 +225,7 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||||
// Determine if each loader can load a context from the mergedConfig. If it
|
// Determine if each loader can load a context from the mergedConfig. If it
|
||||||
// can, let it; otherwise, keep iterating.
|
// can, let it; otherwise, keep iterating.
|
||||||
if (supports(loader, mergedConfig)) {
|
if (supports(loader, mergedConfig)) {
|
||||||
return delegateLoading(loader, mergedConfig);
|
return delegateLoading(loader, mergedConfig, refresh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +233,7 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||||
// ACIs or customizers were declared, then delegate to the annotation config
|
// ACIs or customizers were declared, then delegate to the annotation config
|
||||||
// loader.
|
// loader.
|
||||||
if (!mergedConfig.getContextInitializerClasses().isEmpty() || !mergedConfig.getContextCustomizers().isEmpty()) {
|
if (!mergedConfig.getContextInitializerClasses().isEmpty() || !mergedConfig.getContextCustomizers().isEmpty()) {
|
||||||
return delegateLoading(getAnnotationConfigLoader(), mergedConfig);
|
return delegateLoading(getAnnotationConfigLoader(), mergedConfig, refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
// else...
|
// else...
|
||||||
|
@ -235,13 +251,14 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||||
loader.processContextConfiguration(configAttributes);
|
loader.processContextConfiguration(configAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ApplicationContext delegateLoading(SmartContextLoader loader, MergedContextConfiguration mergedConfig)
|
private static ApplicationContext delegateLoading(
|
||||||
|
SmartContextLoader loader, MergedContextConfiguration mergedConfig, boolean refresh)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(String.format("Delegating to %s to load context from %s.", name(loader), mergedConfig));
|
logger.debug(String.format("Delegating to %s to load context from %s.", name(loader), mergedConfig));
|
||||||
}
|
}
|
||||||
return loader.loadContext(mergedConfig);
|
return loader.loadContext(mergedConfig, refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean supports(SmartContextLoader loader, MergedContextConfiguration mergedConfig) {
|
private boolean supports(SmartContextLoader loader, MergedContextConfiguration mergedConfig) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2021 the original author or authors.
|
* Copyright 2002-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -40,9 +40,9 @@ import org.springframework.util.StringUtils;
|
||||||
* <li>If instances of concrete subclasses are invoked via the
|
* <li>If instances of concrete subclasses are invoked via the
|
||||||
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader}
|
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader}
|
||||||
* SPI, the context will be loaded from the {@link MergedContextConfiguration}
|
* SPI, the context will be loaded from the {@link MergedContextConfiguration}
|
||||||
* provided to {@link #loadContext(MergedContextConfiguration)}. In such cases, a
|
* provided to {@link #loadContext(MergedContextConfiguration, boolean)}. In such
|
||||||
* {@code SmartContextLoader} will decide whether to load the context from
|
* cases, a {@code SmartContextLoader} will decide whether to load the context
|
||||||
* <em>locations</em> or <em>annotated classes</em>.</li>
|
* from <em>locations</em> or <em>annotated classes</em>.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* <p>Concrete subclasses must provide an appropriate implementation of
|
* <p>Concrete subclasses must provide an appropriate implementation of
|
||||||
|
@ -54,13 +54,23 @@ import org.springframework.util.StringUtils;
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @since 2.5
|
* @since 2.5
|
||||||
* @see #loadContext(MergedContextConfiguration)
|
* @see #loadContext(MergedContextConfiguration, boolean)
|
||||||
* @see #loadContext(String...)
|
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractGenericContextLoader extends AbstractContextLoader {
|
public abstract class AbstractGenericContextLoader extends AbstractContextLoader {
|
||||||
|
|
||||||
protected static final Log logger = LogFactory.getLog(AbstractGenericContextLoader.class);
|
protected static final Log logger = LogFactory.getLog(AbstractGenericContextLoader.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Although this method is officially deprecated, for backward compatibility
|
||||||
|
* it delegates to {@link #loadContext(MergedContextConfiguration, boolean)},
|
||||||
|
* supplying {@code true} for the {@code refresh} flag.
|
||||||
|
* @deprecated as of Spring Framework 6.0, in favor of {@link #loadContext(MergedContextConfiguration, boolean)}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
||||||
|
return loadContext(mergedConfig, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a Spring ApplicationContext from the supplied {@link MergedContextConfiguration}.
|
* Load a Spring ApplicationContext from the supplied {@link MergedContextConfiguration}.
|
||||||
|
@ -94,15 +104,22 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||||
* <li>Calls {@link #customizeContext(ConfigurableApplicationContext, MergedContextConfiguration)} to
|
* <li>Calls {@link #customizeContext(ConfigurableApplicationContext, MergedContextConfiguration)} to
|
||||||
* allow for customizing the context before it is refreshed.</li>
|
* allow for customizing the context before it is refreshed.</li>
|
||||||
* <li>{@link ConfigurableApplicationContext#refresh Refreshes} the
|
* <li>{@link ConfigurableApplicationContext#refresh Refreshes} the
|
||||||
* context and registers a JVM shutdown hook for it.</li>
|
* context and registers a JVM shutdown hook for it if the supplied the
|
||||||
|
* {@code refresh} flag is {@code true}.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
* @param mergedConfig the merged context configuration to use to load the
|
||||||
|
* application context
|
||||||
|
* @param refresh whether to refresh the {@code ApplicationContext} and register
|
||||||
|
* a JVM shutdown hook for it
|
||||||
* @return a new application context
|
* @return a new application context
|
||||||
* @since 3.1
|
* @since 6.0
|
||||||
* @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration)
|
* @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration, boolean)
|
||||||
* @see GenericApplicationContext
|
* @see GenericApplicationContext
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final ConfigurableApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
public final ConfigurableApplicationContext loadContext(
|
||||||
|
MergedContextConfiguration mergedConfig, boolean refresh) throws Exception {
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(String.format("Loading ApplicationContext for merged context configuration [%s].",
|
logger.debug(String.format("Loading ApplicationContext for merged context configuration [%s].",
|
||||||
mergedConfig));
|
mergedConfig));
|
||||||
|
@ -124,8 +141,10 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||||
customizeContext(context);
|
customizeContext(context);
|
||||||
customizeContext(context, mergedConfig);
|
customizeContext(context, mergedConfig);
|
||||||
|
|
||||||
|
if (refresh) {
|
||||||
context.refresh();
|
context.refresh();
|
||||||
context.registerShutdownHook();
|
context.registerShutdownHook();
|
||||||
|
}
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
@ -166,15 +185,15 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||||
* context and registers a JVM shutdown hook for it.</li>
|
* context and registers a JVM shutdown hook for it.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* <p><b>Note</b>: this method does not provide a means to set active bean definition
|
* <p><b>Note</b>: this method does not provide a means to set active bean definition
|
||||||
* profiles for the loaded context. See {@link #loadContext(MergedContextConfiguration)}
|
* profiles for the loaded context. See {@link #loadContext(MergedContextConfiguration, boolean)}
|
||||||
* and {@link AbstractContextLoader#prepareContext(ConfigurableApplicationContext, MergedContextConfiguration)}
|
* and {@link AbstractContextLoader#prepareContext(ConfigurableApplicationContext, MergedContextConfiguration)}
|
||||||
* for an alternative.
|
* for an alternative.
|
||||||
* @return a new application context
|
* @return a new application context
|
||||||
* @since 2.5
|
* @since 2.5
|
||||||
* @see org.springframework.test.context.ContextLoader#loadContext
|
* @see org.springframework.test.context.ContextLoader#loadContext
|
||||||
* @see GenericApplicationContext
|
* @see GenericApplicationContext
|
||||||
* @see #loadContext(MergedContextConfiguration)
|
* @see #loadContext(MergedContextConfiguration, boolean)
|
||||||
* @deprecated as of Spring Framework 6.0, in favor of {@link #loadContext(MergedContextConfiguration)}
|
* @deprecated as of Spring Framework 6.0, in favor of {@link #loadContext(MergedContextConfiguration, boolean)}
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@Override
|
@Override
|
||||||
|
@ -219,7 +238,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||||
* customize {@code GenericApplicationContext}'s standard settings.
|
* customize {@code GenericApplicationContext}'s standard settings.
|
||||||
* @param context the context that should be prepared
|
* @param context the context that should be prepared
|
||||||
* @since 2.5
|
* @since 2.5
|
||||||
* @see #loadContext(MergedContextConfiguration)
|
* @see #loadContext(MergedContextConfiguration, boolean)
|
||||||
* @see #loadContext(String...)
|
* @see #loadContext(String...)
|
||||||
* @see GenericApplicationContext#setAllowBeanDefinitionOverriding
|
* @see GenericApplicationContext#setAllowBeanDefinitionOverriding
|
||||||
* @see GenericApplicationContext#setResourceLoader
|
* @see GenericApplicationContext#setResourceLoader
|
||||||
|
@ -236,7 +255,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||||
* to customize {@code DefaultListableBeanFactory}'s standard settings.
|
* to customize {@code DefaultListableBeanFactory}'s standard settings.
|
||||||
* @param beanFactory the bean factory created by this {@code ContextLoader}
|
* @param beanFactory the bean factory created by this {@code ContextLoader}
|
||||||
* @since 2.5
|
* @since 2.5
|
||||||
* @see #loadContext(MergedContextConfiguration)
|
* @see #loadContext(MergedContextConfiguration, boolean)
|
||||||
* @see #loadContext(String...)
|
* @see #loadContext(String...)
|
||||||
* @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
|
* @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
|
||||||
* @see DefaultListableBeanFactory#setAllowEagerClassLoading
|
* @see DefaultListableBeanFactory#setAllowEagerClassLoading
|
||||||
|
@ -261,7 +280,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||||
* @param context the context into which the bean definitions should be loaded
|
* @param context the context into which the bean definitions should be loaded
|
||||||
* @param mergedConfig the merged context configuration
|
* @param mergedConfig the merged context configuration
|
||||||
* @since 3.1
|
* @since 3.1
|
||||||
* @see #loadContext(MergedContextConfiguration)
|
* @see #loadContext(MergedContextConfiguration, boolean)
|
||||||
*/
|
*/
|
||||||
protected void loadBeanDefinitions(GenericApplicationContext context, MergedContextConfiguration mergedConfig) {
|
protected void loadBeanDefinitions(GenericApplicationContext context, MergedContextConfiguration mergedConfig) {
|
||||||
createBeanDefinitionReader(context).loadBeanDefinitions(mergedConfig.getLocations());
|
createBeanDefinitionReader(context).loadBeanDefinitions(mergedConfig.getLocations());
|
||||||
|
@ -288,7 +307,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||||
* to customize the application context.
|
* to customize the application context.
|
||||||
* @param context the newly created application context
|
* @param context the newly created application context
|
||||||
* @since 2.5
|
* @since 2.5
|
||||||
* @see #loadContext(MergedContextConfiguration)
|
* @see #loadContext(MergedContextConfiguration, boolean)
|
||||||
* @see #loadContext(String...)
|
* @see #loadContext(String...)
|
||||||
* @see #customizeContext(ConfigurableApplicationContext, MergedContextConfiguration)
|
* @see #customizeContext(ConfigurableApplicationContext, MergedContextConfiguration)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -64,6 +64,18 @@ public abstract class AbstractGenericWebContextLoader extends AbstractContextLoa
|
||||||
|
|
||||||
// SmartContextLoader
|
// SmartContextLoader
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Although this method is officially deprecated, for backward compatibility
|
||||||
|
* it delegates to {@link #loadContext(MergedContextConfiguration, boolean)},
|
||||||
|
* supplying {@code true} for the {@code refresh} flag.
|
||||||
|
* @deprecated as of Spring Framework 6.0, in favor of {@link #loadContext(MergedContextConfiguration, boolean)}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
||||||
|
return loadContext(mergedConfig, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a Spring {@link WebApplicationContext} from the supplied
|
* Load a Spring {@link WebApplicationContext} from the supplied
|
||||||
* {@link MergedContextConfiguration}.
|
* {@link MergedContextConfiguration}.
|
||||||
|
@ -94,12 +106,19 @@ public abstract class AbstractGenericWebContextLoader extends AbstractContextLoa
|
||||||
* <li>{@link ConfigurableApplicationContext#refresh Refreshes} the
|
* <li>{@link ConfigurableApplicationContext#refresh Refreshes} the
|
||||||
* context and registers a JVM shutdown hook for it.</li>
|
* context and registers a JVM shutdown hook for it.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
* @param mergedConfig the merged context configuration to use to load the
|
||||||
|
* application context
|
||||||
|
* @param refresh whether to refresh the {@code ApplicationContext} and register
|
||||||
|
* a JVM shutdown hook for it
|
||||||
* @return a new web application context
|
* @return a new web application context
|
||||||
* @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration)
|
* @since 6.0
|
||||||
|
* @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration, boolean)
|
||||||
* @see GenericWebApplicationContext
|
* @see GenericWebApplicationContext
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final ConfigurableApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
public final ConfigurableApplicationContext loadContext(
|
||||||
|
MergedContextConfiguration mergedConfig, boolean refresh) throws Exception {
|
||||||
|
|
||||||
Assert.isTrue(mergedConfig instanceof WebMergedContextConfiguration,
|
Assert.isTrue(mergedConfig instanceof WebMergedContextConfiguration,
|
||||||
() -> String.format("Cannot load WebApplicationContext from non-web merged context configuration %s. " +
|
() -> String.format("Cannot load WebApplicationContext from non-web merged context configuration %s. " +
|
||||||
"Consider annotating your test class with @WebAppConfiguration.", mergedConfig));
|
"Consider annotating your test class with @WebAppConfiguration.", mergedConfig));
|
||||||
|
@ -125,8 +144,12 @@ public abstract class AbstractGenericWebContextLoader extends AbstractContextLoa
|
||||||
loadBeanDefinitions(context, webMergedConfig);
|
loadBeanDefinitions(context, webMergedConfig);
|
||||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||||
customizeContext(context, webMergedConfig);
|
customizeContext(context, webMergedConfig);
|
||||||
|
|
||||||
|
if (refresh) {
|
||||||
context.refresh();
|
context.refresh();
|
||||||
context.registerShutdownHook();
|
context.registerShutdownHook();
|
||||||
|
}
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2019 the original author or authors.
|
* Copyright 2002-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -50,7 +50,7 @@ import org.springframework.util.StringUtils;
|
||||||
* @see org.springframework.test.context.ContextConfiguration
|
* @see org.springframework.test.context.ContextConfiguration
|
||||||
* @see org.springframework.test.context.ActiveProfiles
|
* @see org.springframework.test.context.ActiveProfiles
|
||||||
* @see org.springframework.test.context.ContextConfigurationAttributes
|
* @see org.springframework.test.context.ContextConfigurationAttributes
|
||||||
* @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration)
|
* @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration, boolean)
|
||||||
*/
|
*/
|
||||||
public class WebMergedContextConfiguration extends MergedContextConfiguration {
|
public class WebMergedContextConfiguration extends MergedContextConfiguration {
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2012 the original author or authors.
|
* Copyright 2002-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -28,11 +28,11 @@ import org.springframework.context.annotation.Configuration;
|
||||||
*/
|
*/
|
||||||
public class AnnotatedFooConfigInnerClassTestCase {
|
public class AnnotatedFooConfigInnerClassTestCase {
|
||||||
|
|
||||||
@Configuration
|
@Configuration(proxyBeanMethods = false)
|
||||||
static class FooConfig {
|
static class FooConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public String foo() {
|
String foo() {
|
||||||
return "foo";
|
return "foo";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2019 the original author or authors.
|
* Copyright 2002-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,8 +16,11 @@
|
||||||
|
|
||||||
package org.springframework.test.context.support;
|
package org.springframework.test.context.support;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.test.context.MergedContextConfiguration;
|
import org.springframework.test.context.MergedContextConfiguration;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -31,24 +34,54 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||||
*/
|
*/
|
||||||
class AnnotationConfigContextLoaderTests {
|
class AnnotationConfigContextLoaderTests {
|
||||||
|
|
||||||
private final AnnotationConfigContextLoader contextLoader = new AnnotationConfigContextLoader();
|
|
||||||
|
|
||||||
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||||
private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
|
private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
|
||||||
|
|
||||||
|
private final AnnotationConfigContextLoader contextLoader = new AnnotationConfigContextLoader();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 4.0.4
|
* @since 4.0.4
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void configMustNotContainLocations() throws Exception {
|
void loadContextWithConfigContainingLocationsResultsInException() {
|
||||||
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(),
|
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(),
|
||||||
new String[] { "config.xml" }, EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, contextLoader);
|
new String[] { "config.xml" }, EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, contextLoader);
|
||||||
assertThatIllegalStateException().isThrownBy(() ->
|
assertThatIllegalStateException()
|
||||||
contextLoader.loadContext(mergedConfig))
|
.isThrownBy(() -> contextLoader.loadContext(mergedConfig, true))
|
||||||
.withMessageContaining("does not support resource locations");
|
.withMessageContaining("does not support resource locations");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void loadContextHonorsRefreshTrue() throws Exception {
|
||||||
|
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(
|
||||||
|
AnnotatedFooConfigInnerClassTestCase.class, EMPTY_STRING_ARRAY,
|
||||||
|
new Class<?>[] {AnnotatedFooConfigInnerClassTestCase.FooConfig.class},
|
||||||
|
EMPTY_STRING_ARRAY, contextLoader);
|
||||||
|
ConfigurableApplicationContext context = contextLoader.loadContext(mergedConfig, true);
|
||||||
|
assertThat(context).isNotNull();
|
||||||
|
assertThat(context.isActive()).as("ApplicationContext is active").isTrue();
|
||||||
|
assertThat(context.getBean(String.class)).isEqualTo("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void loadContextHonorsRefreshFalse() throws Exception {
|
||||||
|
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(
|
||||||
|
AnnotatedFooConfigInnerClassTestCase.class, EMPTY_STRING_ARRAY,
|
||||||
|
new Class<?>[] {AnnotatedFooConfigInnerClassTestCase.FooConfig.class},
|
||||||
|
EMPTY_STRING_ARRAY, contextLoader);
|
||||||
|
ConfigurableApplicationContext context = contextLoader.loadContext(mergedConfig, false);
|
||||||
|
assertThat(context).isNotNull();
|
||||||
|
assertThat(context.isActive()).as("ApplicationContext is active").isFalse();
|
||||||
|
assertThat(Arrays.stream(context.getBeanDefinitionNames())).anyMatch(name -> name.contains("FooConfig"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void detectDefaultConfigurationClassesForAnnotatedInnerClass() {
|
void detectDefaultConfigurationClassesForAnnotatedInnerClass() {
|
||||||
Class<?>[] configClasses = contextLoader.detectDefaultConfigurationClasses(ContextConfigurationInnerClassTestCase.class);
|
Class<?>[] configClasses = contextLoader.detectDefaultConfigurationClasses(ContextConfigurationInnerClassTestCase.class);
|
||||||
|
|
|
@ -53,7 +53,7 @@ class CustomizedGenericXmlContextLoaderTests {
|
||||||
|
|
||||||
MergedContextConfiguration mergedConfig =
|
MergedContextConfiguration mergedConfig =
|
||||||
new MergedContextConfiguration(getClass(), null, null, null, null);
|
new MergedContextConfiguration(getClass(), null, null, null, null);
|
||||||
customLoader.loadContext(mergedConfig);
|
customLoader.loadContext(mergedConfig, true);
|
||||||
|
|
||||||
assertThat(customizeInvoked).as("customizeContext() should have been invoked").isTrue();
|
assertThat(customizeInvoked).as("customizeContext() should have been invoked").isTrue();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
|
|
||||||
package org.springframework.test.context.support;
|
package org.springframework.test.context.support;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
@ -25,7 +28,6 @@ import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||||
import org.springframework.test.context.ContextLoader;
|
import org.springframework.test.context.ContextLoader;
|
||||||
import org.springframework.test.context.MergedContextConfiguration;
|
import org.springframework.test.context.MergedContextConfiguration;
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
@ -45,20 +47,16 @@ class DelegatingSmartContextLoaderTests {
|
||||||
|
|
||||||
private final DelegatingSmartContextLoader loader = new DelegatingSmartContextLoader();
|
private final DelegatingSmartContextLoader loader = new DelegatingSmartContextLoader();
|
||||||
|
|
||||||
|
@Nested
|
||||||
private static void assertEmpty(Object[] array) {
|
class SmartContextLoaderSpiTests {
|
||||||
assertThat(ObjectUtils.isEmpty(array)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- SmartContextLoader - processContextConfiguration() ------------------
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void processContextConfigurationWithDefaultXmlConfigGeneration() {
|
void processContextConfigurationWithDefaultXmlConfigGeneration() {
|
||||||
ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(
|
ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(
|
||||||
XmlTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class);
|
XmlTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class);
|
||||||
loader.processContextConfiguration(configAttributes);
|
loader.processContextConfiguration(configAttributes);
|
||||||
assertThat(configAttributes.getLocations().length).isEqualTo(1);
|
assertThat(configAttributes.getLocations()).hasSize(1);
|
||||||
assertEmpty(configAttributes.getClasses());
|
assertThat(configAttributes.getClasses()).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -66,8 +64,8 @@ class DelegatingSmartContextLoaderTests {
|
||||||
ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(
|
ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(
|
||||||
ConfigClassTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class);
|
ConfigClassTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class);
|
||||||
loader.processContextConfiguration(configAttributes);
|
loader.processContextConfiguration(configAttributes);
|
||||||
assertThat(configAttributes.getClasses().length).isEqualTo(1);
|
assertThat(configAttributes.getClasses()).hasSize(1);
|
||||||
assertEmpty(configAttributes.getLocations());
|
assertThat(configAttributes.getLocations()).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -75,8 +73,8 @@ class DelegatingSmartContextLoaderTests {
|
||||||
ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(
|
ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(
|
||||||
ImproperDuplicateDefaultXmlAndConfigClassTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY,
|
ImproperDuplicateDefaultXmlAndConfigClassTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY,
|
||||||
true, null, true, ContextLoader.class);
|
true, null, true, ContextLoader.class);
|
||||||
assertThatIllegalStateException().isThrownBy(() ->
|
assertThatIllegalStateException()
|
||||||
loader.processContextConfiguration(configAttributes))
|
.isThrownBy(() -> loader.processContextConfiguration(configAttributes))
|
||||||
.withMessageContaining("both default locations AND default configuration classes were detected");
|
.withMessageContaining("both default locations AND default configuration classes were detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +85,7 @@ class DelegatingSmartContextLoaderTests {
|
||||||
getClass(), locations, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class);
|
getClass(), locations, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class);
|
||||||
loader.processContextConfiguration(configAttributes);
|
loader.processContextConfiguration(configAttributes);
|
||||||
assertThat(configAttributes.getLocations()).isEqualTo(locations);
|
assertThat(configAttributes.getLocations()).isEqualTo(locations);
|
||||||
assertEmpty(configAttributes.getClasses());
|
assertThat(configAttributes.getClasses()).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -97,23 +95,20 @@ class DelegatingSmartContextLoaderTests {
|
||||||
getClass(), EMPTY_STRING_ARRAY, classes, true, null, true, ContextLoader.class);
|
getClass(), EMPTY_STRING_ARRAY, classes, true, null, true, ContextLoader.class);
|
||||||
loader.processContextConfiguration(configAttributes);
|
loader.processContextConfiguration(configAttributes);
|
||||||
assertThat(configAttributes.getClasses()).isEqualTo(classes);
|
assertThat(configAttributes.getClasses()).isEqualTo(classes);
|
||||||
assertEmpty(configAttributes.getLocations());
|
assertThat(configAttributes.getLocations()).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- SmartContextLoader - loadContext() ----------------------------------
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void loadContextWithNullConfig() throws Exception {
|
void loadContextWithNullConfig() throws Exception {
|
||||||
assertThatIllegalArgumentException().isThrownBy(() ->
|
assertThatIllegalArgumentException().isThrownBy(() -> loader.loadContext(null, true));
|
||||||
loader.loadContext((MergedContextConfiguration) null));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void loadContextWithoutLocationsAndConfigurationClasses() throws Exception {
|
void loadContextWithoutLocationsAndConfigurationClasses() throws Exception {
|
||||||
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(
|
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(
|
||||||
getClass(), EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, loader);
|
getClass(), EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, loader);
|
||||||
assertThatIllegalStateException().isThrownBy(() ->
|
assertThatIllegalStateException()
|
||||||
loader.loadContext(mergedConfig))
|
.isThrownBy(() -> loader.loadContext(mergedConfig, true))
|
||||||
.withMessageStartingWith("Neither")
|
.withMessageStartingWith("Neither")
|
||||||
.withMessageContaining("was able to load an ApplicationContext from");
|
.withMessageContaining("was able to load an ApplicationContext from");
|
||||||
}
|
}
|
||||||
|
@ -125,29 +120,19 @@ class DelegatingSmartContextLoaderTests {
|
||||||
void loadContextWithLocationsAndConfigurationClasses() throws Exception {
|
void loadContextWithLocationsAndConfigurationClasses() throws Exception {
|
||||||
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(),
|
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(),
|
||||||
new String[] {"test.xml"}, new Class<?>[] {getClass()}, EMPTY_STRING_ARRAY, loader);
|
new String[] {"test.xml"}, new Class<?>[] {getClass()}, EMPTY_STRING_ARRAY, loader);
|
||||||
assertThatIllegalStateException().isThrownBy(() ->
|
assertThatIllegalStateException()
|
||||||
loader.loadContext(mergedConfig))
|
.isThrownBy(() -> loader.loadContext(mergedConfig, true))
|
||||||
.withMessageStartingWith("Neither")
|
.withMessageStartingWith("Neither")
|
||||||
.withMessageContaining("declare either 'locations' or 'classes' but not both.");
|
.withMessageContaining("declare either 'locations' or 'classes' but not both.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertApplicationContextLoadsAndContainsFooString(MergedContextConfiguration mergedConfig)
|
|
||||||
throws Exception {
|
|
||||||
|
|
||||||
ApplicationContext applicationContext = loader.loadContext(mergedConfig);
|
|
||||||
assertThat(applicationContext).isNotNull();
|
|
||||||
assertThat(applicationContext.getBean(String.class)).isEqualTo("foo");
|
|
||||||
boolean condition = applicationContext instanceof ConfigurableApplicationContext;
|
|
||||||
assertThat(condition).isTrue();
|
|
||||||
((ConfigurableApplicationContext) applicationContext).close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void loadContextWithXmlConfig() throws Exception {
|
void loadContextWithXmlConfig() throws Exception {
|
||||||
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(
|
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(
|
||||||
XmlTestCase.class,
|
XmlTestCase.class,
|
||||||
new String[] {"classpath:/org/springframework/test/context/support/DelegatingSmartContextLoaderTests$XmlTestCase-context.xml"},
|
new String[] {"classpath:/org/springframework/test/context/support/DelegatingSmartContextLoaderTests$XmlTestCase-context.xml"},
|
||||||
EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, loader);
|
EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, loader);
|
||||||
|
|
||||||
assertApplicationContextLoadsAndContainsFooString(mergedConfig);
|
assertApplicationContextLoadsAndContainsFooString(mergedConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,25 +140,74 @@ class DelegatingSmartContextLoaderTests {
|
||||||
void loadContextWithConfigurationClass() throws Exception {
|
void loadContextWithConfigurationClass() throws Exception {
|
||||||
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(ConfigClassTestCase.class,
|
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(ConfigClassTestCase.class,
|
||||||
EMPTY_STRING_ARRAY, new Class<?>[] {ConfigClassTestCase.Config.class}, EMPTY_STRING_ARRAY, loader);
|
EMPTY_STRING_ARRAY, new Class<?>[] {ConfigClassTestCase.Config.class}, EMPTY_STRING_ARRAY, loader);
|
||||||
|
|
||||||
assertApplicationContextLoadsAndContainsFooString(mergedConfig);
|
assertApplicationContextLoadsAndContainsFooString(mergedConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- ContextLoader -------------------------------------------------------
|
private void assertApplicationContextLoadsAndContainsFooString(MergedContextConfiguration mergedConfig)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
ApplicationContext applicationContext = loader.loadContext(mergedConfig, true);
|
||||||
|
assertThat(applicationContext).isInstanceOf(ConfigurableApplicationContext.class);
|
||||||
|
assertThat(applicationContext.getBean(String.class)).isEqualTo("foo");
|
||||||
|
ConfigurableApplicationContext cac = (ConfigurableApplicationContext) applicationContext;
|
||||||
|
cac.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void loadContextWithXmlConfigWithoutRefresh() throws Exception {
|
||||||
|
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(
|
||||||
|
XmlTestCase.class,
|
||||||
|
new String[] {"classpath:/org/springframework/test/context/support/DelegatingSmartContextLoaderTests$XmlTestCase-context.xml"},
|
||||||
|
EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, loader);
|
||||||
|
|
||||||
|
assertApplicationContextLoadsWithoutRefresh(mergedConfig, "foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void loadContextWithConfigurationClassWithoutRefresh() throws Exception {
|
||||||
|
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(ConfigClassTestCase.class,
|
||||||
|
EMPTY_STRING_ARRAY, new Class<?>[] {ConfigClassTestCase.Config.class}, EMPTY_STRING_ARRAY, loader);
|
||||||
|
|
||||||
|
assertApplicationContextLoadsWithoutRefresh(mergedConfig, "ConfigClassTestCase.Config");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertApplicationContextLoadsWithoutRefresh(MergedContextConfiguration mergedConfig,
|
||||||
|
String expectedBeanDefName) throws Exception {
|
||||||
|
|
||||||
|
ApplicationContext context = loader.loadContext(mergedConfig, false);
|
||||||
|
assertThat(context).isInstanceOf(ConfigurableApplicationContext.class);
|
||||||
|
ConfigurableApplicationContext cac = (ConfigurableApplicationContext) context;
|
||||||
|
assertThat(cac.isActive()).as("ApplicationContext is active").isFalse();
|
||||||
|
assertThat(Arrays.stream(context.getBeanDefinitionNames())).anyMatch(name -> name.contains(expectedBeanDefName));
|
||||||
|
cac.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class ContextLoaderSpiTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void processLocations() {
|
void processLocations() {
|
||||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() ->
|
assertThatExceptionOfType(UnsupportedOperationException.class)
|
||||||
loader.processLocations(getClass(), EMPTY_STRING_ARRAY));
|
.isThrownBy(() -> loader.processLocations(getClass(), EMPTY_STRING_ARRAY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void loadContextFromLocations() {
|
void loadContextFromLocations() {
|
||||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() ->
|
assertThatExceptionOfType(UnsupportedOperationException.class)
|
||||||
loader.loadContext(EMPTY_STRING_ARRAY));
|
.isThrownBy(() -> loader.loadContext(EMPTY_STRING_ARRAY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static class XmlTestCase {
|
static class XmlTestCase {
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2019 the original author or authors.
|
* Copyright 2002-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -40,7 +40,7 @@ class GenericXmlContextLoaderTests {
|
||||||
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(), EMPTY_STRING_ARRAY,
|
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(), EMPTY_STRING_ARRAY,
|
||||||
new Class<?>[] { getClass() }, EMPTY_STRING_ARRAY, loader);
|
new Class<?>[] { getClass() }, EMPTY_STRING_ARRAY, loader);
|
||||||
assertThatIllegalStateException()
|
assertThatIllegalStateException()
|
||||||
.isThrownBy(() -> loader.loadContext(mergedConfig))
|
.isThrownBy(() -> loader.loadContext(mergedConfig, true))
|
||||||
.withMessageContaining("does not support annotated classes");
|
.withMessageContaining("does not support annotated classes");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2019 the original author or authors.
|
* Copyright 2002-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -39,7 +39,7 @@ class AnnotationConfigWebContextLoaderTests {
|
||||||
new String[] { "config.xml" }, EMPTY_CLASS_ARRAY, null, EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY,
|
new String[] { "config.xml" }, EMPTY_CLASS_ARRAY, null, EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY,
|
||||||
EMPTY_STRING_ARRAY, "resource/path", loader, null, null);
|
EMPTY_STRING_ARRAY, "resource/path", loader, null, null);
|
||||||
assertThatIllegalStateException()
|
assertThatIllegalStateException()
|
||||||
.isThrownBy(() -> loader.loadContext(mergedConfig))
|
.isThrownBy(() -> loader.loadContext(mergedConfig, true))
|
||||||
.withMessageContaining("does not support resource locations");
|
.withMessageContaining("does not support resource locations");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2019 the original author or authors.
|
* Copyright 2002-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -38,7 +38,7 @@ class GenericXmlWebContextLoaderTests {
|
||||||
new Class<?>[] { getClass() }, null, EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY,
|
new Class<?>[] { getClass() }, null, EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY,
|
||||||
"resource/path", loader, null, null);
|
"resource/path", loader, null, null);
|
||||||
assertThatIllegalStateException()
|
assertThatIllegalStateException()
|
||||||
.isThrownBy(() -> loader.loadContext(mergedConfig))
|
.isThrownBy(() -> loader.loadContext(mergedConfig, true))
|
||||||
.withMessageContaining("does not support annotated classes");
|
.withMessageContaining("does not support annotated classes");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue