@ -27,6 +27,7 @@ import java.util.Set;
@@ -27,6 +27,7 @@ import java.util.Set;
import org.apache.commons.logging.Log ;
import org.apache.commons.logging.LogFactory ;
import org.springframework.beans.BeanInstantiationException ;
import org.springframework.beans.BeanUtils ;
import org.springframework.context.ApplicationContextInitializer ;
import org.springframework.context.ConfigurableApplicationContext ;
@ -57,9 +58,10 @@ import org.springframework.util.StringUtils;
@@ -57,9 +58,10 @@ import org.springframework.util.StringUtils;
* < p > Concrete subclasses typically will only need to provide implementations for
* the following { @code abstract } methods :
* < ul >
* < li > { @link # getDefaultTestExecutionListenerClassNames ( ) }
* < li > { @link # getDefaultContextLoaderClass ( Class ) }
* < li > { @link # buildMergedContextConfiguration ( Class , String [ ] , Class [ ] , Set , String [ ] , ContextLoader , CacheAwareContextLoaderDelegate , MergedContextConfiguration ) }
* < li > { @link # getDefaultTestExecutionListenerClassNames }
* < li > { @link # getDefaultContextLoaderClass }
* < li > { @link # buildMergedContextConfiguration }
* < / ul >
*
* @author Sam Brannen
* @since 4 . 1
@ -111,24 +113,22 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
@@ -111,24 +113,22 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
// Traverse the class hierarchy...
while ( descriptor ! = null ) {
Class < ? > declaringClass = descriptor . getDeclaringClass ( ) ;
AnnotationAttributes annAttrs = descriptor . getAnnotationAttributes ( ) ;
if ( logger . isTraceEnabled ( ) ) {
logger . trace ( String . format (
"Retrieved @TestExecutionListeners attributes [%s] for declaring class [%s]." , annAttrs ,
declaringClass ) ) ;
logger . trace ( String . format ( "Retrieved @TestExecutionListeners attributes [%s] for declaring class [%s]." ,
annAttrs , declaringClass ) ) ;
}
Class < ? extends TestExecutionListener > [ ] valueListenerClasses = ( Class < ? extends TestExecutionListener > [ ] ) annAttrs . getClassArray ( "value" ) ;
Class < ? extends TestExecutionListener > [ ] listenerClasses = ( Class < ? extends TestExecutionListener > [ ] ) annAttrs . getClassArray ( "listeners" ) ;
Class < ? extends TestExecutionListener > [ ] valueListenerClasses =
( Class < ? extends TestExecutionListener > [ ] ) annAttrs . getClassArray ( "value" ) ;
Class < ? extends TestExecutionListener > [ ] listenerClasses =
( Class < ? extends TestExecutionListener > [ ] ) annAttrs . getClassArray ( "listeners" ) ;
if ( ! ObjectUtils . isEmpty ( valueListenerClasses ) & & ! ObjectUtils . isEmpty ( listenerClasses ) ) {
String msg = String . format (
"Class [%s] has been configured with @TestExecutionListeners' 'value' [%s] " +
"and 'listeners' [%s] attributes. Use one or the other, but not both." ,
throw new IllegalStateException (
String . format ( "Class [%s] has been configured with @TestExecutionListeners' 'value' [%s]" +
" and 'listeners' [%s] attributes. Use one or the other, but not both." ,
declaringClass , ObjectUtils . nullSafeToString ( valueListenerClasses ) ,
ObjectUtils . nullSafeToString ( listenerClasses ) ) ;
logger . error ( msg ) ;
throw new IllegalStateException ( msg ) ;
ObjectUtils . nullSafeToString ( listenerClasses ) ) ) ;
}
else if ( ! ObjectUtils . isEmpty ( valueListenerClasses ) ) {
listenerClasses = valueListenerClasses ;
@ -137,7 +137,6 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
@@ -137,7 +137,6 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
if ( listenerClasses ! = null ) {
classesList . addAll ( 0 , Arrays . < Class < ? extends TestExecutionListener > > asList ( listenerClasses ) ) ;
}
descriptor = ( annAttrs . getBoolean ( "inheritListeners" ) ? MetaAnnotationUtils . findAnnotationDescriptor (
descriptor . getRootDeclaringClass ( ) . getSuperclass ( ) , annotationType ) : null ) ;
}
@ -145,14 +144,24 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
@@ -145,14 +144,24 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
List < TestExecutionListener > listeners = new ArrayList < TestExecutionListener > ( classesList . size ( ) ) ;
for ( Class < ? extends TestExecutionListener > listenerClass : classesList ) {
NoClassDefFoundError ncdfe = null ;
try {
listeners . add ( BeanUtils . instantiateClass ( listenerClass ) ) ;
}
catch ( NoClassDefFoundError err ) {
ncdfe = err ;
}
catch ( BeanInstantiationException ex ) {
if ( ex . getCause ( ) instanceof NoClassDefFoundError ) {
ncdfe = ( NoClassDefFoundError ) ex . getCause ( ) ;
}
}
if ( ncdfe ! = null ) {
if ( logger . isInfoEnabled ( ) ) {
logger . info ( String . format ( "Could not instantiate TestExecutionListener [%s]. " +
"Specify custom listener classes or make the default listener classes " +
"(and their dependencies) available." , listenerClass . getName ( ) ) ) ;
"(and their dependencies) available. Offending class: [%s]" ,
listenerClass . getName ( ) , ncdfe . getMessage ( ) ) ) ;
}
}
}
@ -197,16 +206,15 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
@@ -197,16 +206,15 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
if ( MetaAnnotationUtils . findAnnotationDescriptorForTypes ( testClass , ContextConfiguration . class ,
ContextHierarchy . class ) = = null ) {
if ( logger . isInfoEnabled ( ) ) {
logger . info ( String . format (
"Neither @ContextConfiguration nor @ContextHierarchy found for test class [%s]" ,
logger . info ( String . format ( "Neither @ContextConfiguration nor @ContextHierarchy found for test class [%s]" ,
testClass . getName ( ) ) ) ;
}
return new MergedContextConfiguration ( testClass , null , null , null , null ) ;
}
if ( AnnotationUtils . findAnnotation ( testClass , ContextHierarchy . class ) ! = null ) {
Map < String , List < ContextConfigurationAttributes > > hierarchyMap = ContextLoaderUtils . buildContextHierarchyMap ( testClass ) ;
Map < String , List < ContextConfigurationAttributes > > hierarchyMap =
ContextLoaderUtils . buildContextHierarchyMap ( testClass ) ;
MergedContextConfiguration parentConfig = null ;
MergedContextConfiguration mergedConfig = null ;
@ -220,8 +228,8 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
@@ -220,8 +228,8 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
Assert . notEmpty ( reversedList , "ContextConfigurationAttributes list must not be empty" ) ;
Class < ? > declaringClass = reversedList . get ( 0 ) . getDeclaringClass ( ) ;
mergedConfig = buildMergedContextConfiguration ( declaringClass , reversedList , parentConfig ,
cacheAwareContextLoaderDelegate ) ;
mergedConfig = buildMergedContextConfiguration (
declaringClass , reversedList , parentConfig , cacheAwareContextLoaderDelegate ) ;
parentConfig = mergedConfig ;
}
@ -257,20 +265,19 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
@@ -257,20 +265,19 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
* @see ApplicationContextInitializerUtils # resolveInitializerClasses
* @see MergedContextConfiguration
* /
private MergedContextConfiguration buildMergedContextConfiguration ( final Class < ? > testClass ,
final List < ContextConfigurationAttributes > configAttributesList , MergedContextConfiguration parentConfig ,
private MergedContextConfiguration buildMergedContextConfiguration ( Class < ? > testClass ,
List < ContextConfigurationAttributes > configAttributesList , MergedContextConfiguration parentConfig ,
CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate ) {
final ContextLoader contextLoader = resolveContextLoader ( testClass , configAttributesList ) ;
final List < String > locationsList = new ArrayList < String > ( ) ;
final List < Class < ? > > classesList = new ArrayList < Class < ? > > ( ) ;
ContextLoader contextLoader = resolveContextLoader ( testClass , configAttributesList ) ;
List < String > locationsList = new ArrayList < String > ( ) ;
List < Class < ? > > classesList = new ArrayList < Class < ? > > ( ) ;
for ( ContextConfigurationAttributes configAttributes : configAttributesList ) {
if ( logger . isTraceEnabled ( ) ) {
logger . trace ( String . format ( "Processing locations and classes for context configuration attributes %s" ,
configAttributes ) ) ;
}
if ( contextLoader instanceof SmartContextLoader ) {
SmartContextLoader smartContextLoader = ( SmartContextLoader ) contextLoader ;
smartContextLoader . processContextConfiguration ( configAttributes ) ;
@ -283,7 +290,6 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
@@ -283,7 +290,6 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
locationsList . addAll ( 0 , Arrays . asList ( processedLocations ) ) ;
// Legacy ContextLoaders don't know how to process classes
}
if ( ! configAttributes . isInheritLocations ( ) ) {
break ;
}
@ -408,8 +414,8 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
@@ -408,8 +414,8 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
* @param initializerClasses the merged context initializer classes
* @param activeProfiles the merged active bean definition profiles
* @param contextLoader the resolved { @code ContextLoader }
* @param cacheAwareContextLoaderDelegate the cache - aware context loader delegate to
* be provided to the instantiated { @code MergedContextConfiguration }
* @param cacheAwareContextLoaderDelegate the cache - aware context loader delegate
* to be provided to the instantiated { @code MergedContextConfiguration }
* @param parentConfig the merged context configuration for the parent application
* context in a context hierarchy , or { @code null } if there is no parent
* @return the fully initialized { @code MergedContextConfiguration }