19
19
import static org .springframework .beans .BeanUtils .*;
20
20
import static org .springframework .core .annotation .AnnotationUtils .*;
21
21
22
+ import java .lang .annotation .Annotation ;
23
+ import java .lang .reflect .Constructor ;
22
24
import java .util .ArrayList ;
23
25
import java .util .Arrays ;
24
26
import java .util .HashSet ;
27
29
28
30
import org .apache .commons .logging .Log ;
29
31
import org .apache .commons .logging .LogFactory ;
32
+
30
33
import org .springframework .context .ApplicationContextInitializer ;
31
34
import org .springframework .context .ConfigurableApplicationContext ;
32
- import org .springframework .test .context .web .WebAppConfiguration ;
33
- import org .springframework .test .context .web .WebMergedContextConfiguration ;
35
+ import org .springframework .core .annotation .AnnotationUtils ;
34
36
import org .springframework .util .Assert ;
35
37
import org .springframework .util .ClassUtils ;
36
38
import org .springframework .util .ObjectUtils ;
@@ -57,6 +59,9 @@ abstract class ContextLoaderUtils {
57
59
private static final String DEFAULT_CONTEXT_LOADER_CLASS_NAME = "org.springframework.test.context.support.DelegatingSmartContextLoader" ;
58
60
private static final String DEFAULT_WEB_CONTEXT_LOADER_CLASS_NAME = "org.springframework.test.context.support.WebDelegatingSmartContextLoader" ;
59
61
62
+ private static final String WEB_APP_CONFIGURATION_CLASS_NAME = "org.springframework.test.context.web.WebAppConfiguration" ;
63
+ private static final String WEB_MERGED_CONTEXT_CONFIGURATION_CLASS_NAME = "org.springframework.test.context.web.WebMergedContextConfiguration" ;
64
+
60
65
61
66
private ContextLoaderUtils () {
62
67
/* no-op */
@@ -69,7 +74,8 @@ private ContextLoaderUtils() {
69
74
*
70
75
* <p>If the supplied <code>defaultContextLoaderClassName</code> is
71
76
* {@code null} or <em>empty</em>, depending on the absence or presence
72
- * of @{@link WebAppConfiguration} either {@value #DEFAULT_CONTEXT_LOADER_CLASS_NAME}
77
+ * of {@link org.springframework.test.context.web.WebAppConfiguration @WebAppConfiguration}
78
+ * either {@value #DEFAULT_CONTEXT_LOADER_CLASS_NAME}
73
79
* or {@value #DEFAULT_WEB_CONTEXT_LOADER_CLASS_NAME} will be used as the
74
80
* default context loader class name. For details on the class resolution
75
81
* process, see {@link #resolveContextLoaderClass()}.
@@ -91,7 +97,9 @@ static ContextLoader resolveContextLoader(Class<?> testClass,
91
97
Assert .notEmpty (configAttributesList , "ContextConfigurationAttributes list must not be empty" );
92
98
93
99
if (!StringUtils .hasText (defaultContextLoaderClassName )) {
94
- defaultContextLoaderClassName = testClass .isAnnotationPresent (WebAppConfiguration .class ) ? DEFAULT_WEB_CONTEXT_LOADER_CLASS_NAME
100
+ Class <? extends Annotation > webAppConfigClass = loadWebAppConfigurationClass ();
101
+ defaultContextLoaderClassName = webAppConfigClass != null
102
+ && testClass .isAnnotationPresent (webAppConfigClass ) ? DEFAULT_WEB_CONTEXT_LOADER_CLASS_NAME
95
103
: DEFAULT_CONTEXT_LOADER_CLASS_NAME ;
96
104
}
97
105
@@ -385,16 +393,82 @@ static MergedContextConfiguration buildMergedContextConfiguration(Class<?> testC
385
393
Set <Class <? extends ApplicationContextInitializer <? extends ConfigurableApplicationContext >>> initializerClasses = resolveInitializerClasses (configAttributesList );
386
394
String [] activeProfiles = resolveActiveProfiles (testClass );
387
395
388
- if (testClass .isAnnotationPresent (WebAppConfiguration .class )) {
389
- WebAppConfiguration webAppConfig = testClass .getAnnotation (WebAppConfiguration .class );
390
- String resourceBasePath = webAppConfig .value ();
391
- return new WebMergedContextConfiguration (testClass , locations , classes , initializerClasses , activeProfiles ,
392
- resourceBasePath , contextLoader );
396
+ MergedContextConfiguration mergedConfig = buildWebMergedContextConfiguration (testClass , locations , classes ,
397
+ initializerClasses , activeProfiles , contextLoader );
398
+
399
+ if (mergedConfig == null ) {
400
+ mergedConfig = new MergedContextConfiguration (testClass , locations , classes , initializerClasses ,
401
+ activeProfiles , contextLoader );
402
+ }
403
+
404
+ return mergedConfig ;
405
+ }
406
+
407
+ /**
408
+ * Load the {@link org.springframework.test.context.web.WebAppConfiguration @WebAppConfiguration}
409
+ * class using reflection in order to avoid package cycles.
410
+ *
411
+ * @return the {@code @WebAppConfiguration} class or <code>null</code> if it
412
+ * cannot be loaded
413
+ */
414
+ @ SuppressWarnings ("unchecked" )
415
+ private static Class <? extends Annotation > loadWebAppConfigurationClass () {
416
+ Class <? extends Annotation > webAppConfigClass = null ;
417
+ try {
418
+ webAppConfigClass = (Class <? extends Annotation >) ClassUtils .forName (WEB_APP_CONFIGURATION_CLASS_NAME ,
419
+ ContextLoaderUtils .class .getClassLoader ());
420
+ }
421
+ catch (Throwable t ) {
422
+ if (logger .isDebugEnabled ()) {
423
+ logger .debug ("Could not load @WebAppConfiguration class [" + WEB_APP_CONFIGURATION_CLASS_NAME + "]." , t );
424
+ }
425
+ }
426
+ return webAppConfigClass ;
427
+ }
428
+
429
+ /**
430
+ * Attempt to build a {@link org.springframework.test.context.web.WebMergedContextConfiguration
431
+ * WebMergedContextConfiguration} from the supplied arguments using reflection
432
+ * in order to avoid package cycles.
433
+ *
434
+ * @return the {@code WebMergedContextConfiguration} or <code>null</code> if
435
+ * it could not be built
436
+ */
437
+ @ SuppressWarnings ("unchecked" )
438
+ private static MergedContextConfiguration buildWebMergedContextConfiguration (
439
+ Class <?> testClass ,
440
+ String [] locations ,
441
+ Class <?>[] classes ,
442
+ Set <Class <? extends ApplicationContextInitializer <? extends ConfigurableApplicationContext >>> initializerClasses ,
443
+ String [] activeProfiles , ContextLoader contextLoader ) {
444
+
445
+ Class <? extends Annotation > webAppConfigClass = loadWebAppConfigurationClass ();
446
+
447
+ if (webAppConfigClass != null && testClass .isAnnotationPresent (webAppConfigClass )) {
448
+ Annotation annotation = testClass .getAnnotation (webAppConfigClass );
449
+ String resourceBasePath = (String ) AnnotationUtils .getValue (annotation );
450
+
451
+ try {
452
+ Class <? extends MergedContextConfiguration > webMergedConfigClass = (Class <? extends MergedContextConfiguration >) ClassUtils .forName (
453
+ WEB_MERGED_CONTEXT_CONFIGURATION_CLASS_NAME , ContextLoaderUtils .class .getClassLoader ());
454
+
455
+ Constructor <? extends MergedContextConfiguration > constructor = ClassUtils .getConstructorIfAvailable (
456
+ webMergedConfigClass , Class .class , String [].class , Class [].class , Set .class , String [].class ,
457
+ String .class , ContextLoader .class );
458
+
459
+ if (constructor != null ) {
460
+ return instantiateClass (constructor , testClass , locations , classes , initializerClasses ,
461
+ activeProfiles , resourceBasePath , contextLoader );
462
+ }
463
+ }
464
+ catch (Throwable t ) {
465
+ if (logger .isDebugEnabled ()) {
466
+ logger .debug ("Could not instantiate [" + WEB_MERGED_CONTEXT_CONFIGURATION_CLASS_NAME + "]." , t );
467
+ }
468
+ }
393
469
}
394
470
395
- // else
396
- return new MergedContextConfiguration (testClass , locations , classes , initializerClasses , activeProfiles ,
397
- contextLoader );
471
+ return null ;
398
472
}
399
473
400
474
}
0 commit comments