diff --git a/spring-test/src/main/java/org/springframework/test/context/CacheAwareContextLoaderDelegate.java b/spring-test/src/main/java/org/springframework/test/context/CacheAwareContextLoaderDelegate.java index e1985e6202..37244cd46b 100644 --- a/spring-test/src/main/java/org/springframework/test/context/CacheAwareContextLoaderDelegate.java +++ b/spring-test/src/main/java/org/springframework/test/context/CacheAwareContextLoaderDelegate.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,30 @@ import org.springframework.test.annotation.DirtiesContext.HierarchyMode; */ public interface CacheAwareContextLoaderDelegate { + /** + * Determine if the {@linkplain ApplicationContext application context} for + * the supplied {@link MergedContextConfiguration} has been loaded (i.e., + * is present in the {@code ContextCache}). + *
Implementations of this method must not load the + * application context as a side effect. In addition, implementations of + * this method should not log the cache statistics via + * {@link org.springframework.test.context.cache.ContextCache#logStatistics()}. + *
The default implementation of this method always returns {@code false}. + * Custom {@code CacheAwareContextLoaderDelegate} implementations are + * therefore highly encouraged to override this method with a more meaningful + * implementation. Note that the standard {@code CacheAwareContextLoaderDelegate} + * implementation in Spring overrides this method appropriately. + * @param mergedContextConfiguration the merged context configuration used + * to load the application context; never {@code null} + * @return {@code true} if the the application context has been loaded + * @since 5.2 + * @see #loadContext + * @see #closeContext + */ + default boolean isContextLoaded(MergedContextConfiguration mergedContextConfiguration) { + return false; + } + /** * Load the {@linkplain ApplicationContext application context} for the supplied * {@link MergedContextConfiguration} by delegating to the {@link ContextLoader} @@ -49,6 +73,8 @@ public interface CacheAwareContextLoaderDelegate { * @return the application context (never {@code null}) * @throws IllegalStateException if an error occurs while retrieving or loading * the application context + * @see #isContextLoaded + * @see #closeContext */ ApplicationContext loadContext(MergedContextConfiguration mergedContextConfiguration); @@ -69,6 +95,8 @@ public interface CacheAwareContextLoaderDelegate { * @param hierarchyMode the hierarchy mode; may be {@code null} if the context * is not part of a hierarchy * @since 4.1 + * @see #isContextLoaded + * @see #loadContext */ void closeContext(MergedContextConfiguration mergedContextConfiguration, @Nullable HierarchyMode hierarchyMode); diff --git a/spring-test/src/main/java/org/springframework/test/context/TestContext.java b/spring-test/src/main/java/org/springframework/test/context/TestContext.java index 48d3b6ebfb..1c1585ff53 100644 --- a/spring-test/src/main/java/org/springframework/test/context/TestContext.java +++ b/spring-test/src/main/java/org/springframework/test/context/TestContext.java @@ -41,8 +41,28 @@ import org.springframework.test.annotation.DirtiesContext.HierarchyMode; * @see TestContextManager * @see TestExecutionListener */ +// Suppression required due to bug in javac in Java 8: presence of default method in a Serializable interface +@SuppressWarnings("serial") public interface TestContext extends AttributeAccessor, Serializable { + /** + * Determine if the {@linkplain ApplicationContext application context} for + * this test context is known to be available. + *
If this method returns {@code true}, a subsequent invocation of + * {@link #getApplicationContext()} should succeed. + *
The default implementation of this method always returns {@code false}. + * Custom {@code TestContext} implementations are therefore highly encouraged + * to override this method with a more meaningful implementation. Note that + * the standard {@code TestContext} implementation in Spring overrides this + * method appropriately. + * @return {@code true} if the application context has already been loaded + * @since 5.2 + * @see #getApplicationContext() + */ + default boolean hasApplicationContext() { + return false; + } + /** * Get the {@linkplain ApplicationContext application context} for this * test context, possibly cached. @@ -52,6 +72,7 @@ public interface TestContext extends AttributeAccessor, Serializable { * @return the application context (never {@code null}) * @throws IllegalStateException if an error occurs while retrieving the * application context + * @see #hasApplicationContext() */ ApplicationContext getApplicationContext(); diff --git a/spring-test/src/main/java/org/springframework/test/context/cache/DefaultCacheAwareContextLoaderDelegate.java b/spring-test/src/main/java/org/springframework/test/context/cache/DefaultCacheAwareContextLoaderDelegate.java index 119bb67bfc..8bf77204e9 100644 --- a/spring-test/src/main/java/org/springframework/test/context/cache/DefaultCacheAwareContextLoaderDelegate.java +++ b/spring-test/src/main/java/org/springframework/test/context/cache/DefaultCacheAwareContextLoaderDelegate.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,7 @@ import org.springframework.util.Assert; /** * Default implementation of the {@link CacheAwareContextLoaderDelegate} interface. * - *
To use a static {@code DefaultContextCache}, invoke the + *
To use a static {@link DefaultContextCache}, invoke the * {@link #DefaultCacheAwareContextLoaderDelegate()} constructor; otherwise, * invoke the {@link #DefaultCacheAwareContextLoaderDelegate(ContextCache)} * and provide a custom {@link ContextCache} implementation. @@ -108,6 +108,13 @@ public class DefaultCacheAwareContextLoaderDelegate implements CacheAwareContext return applicationContext; } + @Override + public boolean isContextLoaded(MergedContextConfiguration mergedContextConfiguration) { + synchronized (this.contextCache) { + return this.contextCache.contains(mergedContextConfiguration); + } + } + @Override public ApplicationContext loadContext(MergedContextConfiguration mergedContextConfiguration) { synchronized (this.contextCache) { diff --git a/spring-test/src/main/java/org/springframework/test/context/support/DefaultTestContext.java b/spring-test/src/main/java/org/springframework/test/context/support/DefaultTestContext.java index 8c5f507814..7f0c97ae46 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/DefaultTestContext.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/DefaultTestContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -95,13 +95,27 @@ public class DefaultTestContext implements TestContext { this.cacheAwareContextLoaderDelegate = cacheAwareContextLoaderDelegate; } + /** + * Determine if the {@linkplain ApplicationContext application context} for + * this test context is present in the context cache. + * @return {@code true} if the application context has already been loaded + * and stored in the context cache + * @since 5.2 + * @see #getApplicationContext() + * @see CacheAwareContextLoaderDelegate#isContextLoaded + */ + @Override + public boolean hasApplicationContext() { + return this.cacheAwareContextLoaderDelegate.isContextLoaded(this.mergedContextConfiguration); + } + /** * Get the {@linkplain ApplicationContext application context} for this * test context. *
The default implementation delegates to the {@link CacheAwareContextLoaderDelegate} * that was supplied when this {@code TestContext} was constructed. * @throws IllegalStateException if the context returned by the context - * loader delegate is not active (i.e., has been closed). + * loader delegate is not active (i.e., has been closed) * @see CacheAwareContextLoaderDelegate#loadContext */ public ApplicationContext getApplicationContext() {