public WebDelegatingSmartContextLoader() { if (groovyPresent) { try { Class<?> loaderClass = ClassUtils.forName(GROOVY_XML_WEB_CONTEXT_LOADER_CLASS_NAME, WebDelegatingSmartContextLoader.class.getClassLoader()); this.xmlLoader = (SmartContextLoader) BeanUtils.instantiateClass(loaderClass); } catch (Throwable ex) { throw new IllegalStateException("Failed to enable support for Groovy scripts; " + "could not load class: " + GROOVY_XML_WEB_CONTEXT_LOADER_CLASS_NAME, ex); } } else { this.xmlLoader = new GenericXmlWebContextLoader(); } this.annotationConfigLoader = new AnnotationConfigWebContextLoader(); }
public DelegatingSmartContextLoader() { if (groovyPresent) { try { Class<?> loaderClass = ClassUtils.forName(GROOVY_XML_CONTEXT_LOADER_CLASS_NAME, DelegatingSmartContextLoader.class.getClassLoader()); this.xmlLoader = (SmartContextLoader) BeanUtils.instantiateClass(loaderClass); } catch (Throwable ex) { throw new IllegalStateException("Failed to enable support for Groovy scripts; " + "could not load class: " + GROOVY_XML_CONTEXT_LOADER_CLASS_NAME, ex); } } else { this.xmlLoader = new GenericXmlContextLoader(); } this.annotationConfigLoader = new AnnotationConfigContextLoader(); }
/** * Load the {@code ApplicationContext} for the supplied merged context configuration. * <p>Supports both the {@link SmartContextLoader} and {@link ContextLoader} SPIs. * @throws Exception if an error occurs while loading the application context */ protected ApplicationContext loadContextInternal(MergedContextConfiguration mergedContextConfiguration) throws Exception { ContextLoader contextLoader = mergedContextConfiguration.getContextLoader(); Assert.notNull(contextLoader, "Cannot load an ApplicationContext with a NULL 'contextLoader'. " + "Consider annotating your test class with @ContextConfiguration or @ContextHierarchy."); ApplicationContext applicationContext; if (contextLoader instanceof SmartContextLoader) { SmartContextLoader smartContextLoader = (SmartContextLoader) contextLoader; applicationContext = smartContextLoader.loadContext(mergedContextConfiguration); } else { String[] locations = mergedContextConfiguration.getLocations(); Assert.notNull(locations, "Cannot load an ApplicationContext with a NULL 'locations' array. " + "Consider annotating your test class with @ContextConfiguration or @ContextHierarchy."); applicationContext = contextLoader.loadContext(locations); } return applicationContext; }
/** * Delegates to an appropriate candidate {@code SmartContextLoader} to load * an {@link ApplicationContext}. * * <p>Delegation is based on explicit knowledge of the implementations of the * default loaders for {@link #getXmlLoader() XML configuration files} and * {@link #getAnnotationConfigLoader() annotated classes}. Specifically, the * delegation algorithm is as follows: * * <ul> * <li>If the resource locations in the supplied {@code MergedContextConfiguration} * are not empty and the annotated classes are empty, * the XML-based loader will load the {@code ApplicationContext}.</li> * <li>If the annotated classes in the supplied {@code MergedContextConfiguration} * are not empty and the resource locations are empty, * the annotation-based loader will load the {@code ApplicationContext}.</li> * </ul> * * @param mergedConfig the merged context configuration to use to load the application context * @throws IllegalArgumentException if the supplied merged configuration is {@code null} * @throws IllegalStateException if neither candidate loader is capable of loading an * {@code ApplicationContext} from the supplied merged context configuration */ public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception { Assert.notNull(mergedConfig, "mergedConfig must not be null"); List<SmartContextLoader> candidates = Arrays.asList(getXmlLoader(), getAnnotationConfigLoader()); for (SmartContextLoader loader : candidates) { // Determine if each loader can load a context from the mergedConfig. If it // can, let it; otherwise, keep iterating. if (supports(loader, mergedConfig)) { return delegateLoading(loader, mergedConfig); } } // If neither of the candidates supports the mergedConfig based on resources but // ACIs were declared, then delegate to the annotation config loader. if (!mergedConfig.getContextInitializerClasses().isEmpty()) { return delegateLoading(getAnnotationConfigLoader(), mergedConfig); } throw new IllegalStateException(String.format( "Neither %s nor %s was able to load an ApplicationContext from %s.", name(getXmlLoader()), name(getAnnotationConfigLoader()), mergedConfig)); }
private static void delegateProcessing(SmartContextLoader loader, ContextConfigurationAttributes configAttributes) { if (logger.isDebugEnabled()) { logger.debug(String.format("Delegating to %s to process context configuration %s.", name(loader), configAttributes)); } loader.processContextConfiguration(configAttributes); }
private static ApplicationContext delegateLoading(SmartContextLoader loader, MergedContextConfiguration mergedConfig) throws Exception { if (logger.isDebugEnabled()) { logger.debug(String.format("Delegating to %s to load context from %s.", name(loader), mergedConfig)); } return loader.loadContext(mergedConfig); }
private boolean supports(SmartContextLoader loader, MergedContextConfiguration mergedConfig) { if (loader == getAnnotationConfigLoader()) { return mergedConfig.hasClasses() && !mergedConfig.hasLocations(); } else { return mergedConfig.hasLocations() && !mergedConfig.hasClasses(); } }
/** * Delegates to an appropriate candidate {@code SmartContextLoader} to load * an {@link ApplicationContext}. * <p>Delegation is based on explicit knowledge of the implementations of the * default loaders for {@linkplain #getXmlLoader() XML configuration files and * Groovy scripts} and {@linkplain #getAnnotationConfigLoader() annotated classes}. * Specifically, the delegation algorithm is as follows: * <ul> * <li>If the resource locations in the supplied {@code MergedContextConfiguration} * are not empty and the annotated classes are empty, * the XML-based loader will load the {@code ApplicationContext}.</li> * <li>If the annotated classes in the supplied {@code MergedContextConfiguration} * are not empty and the resource locations are empty, * the annotation-based loader will load the {@code ApplicationContext}.</li> * </ul> * @param mergedConfig the merged context configuration to use to load the application context * @throws IllegalArgumentException if the supplied merged configuration is {@code null} * @throws IllegalStateException if neither candidate loader is capable of loading an * {@code ApplicationContext} from the supplied merged context configuration */ @Override public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception { Assert.notNull(mergedConfig, "mergedConfig must not be null"); List<SmartContextLoader> candidates = Arrays.asList(getXmlLoader(), getAnnotationConfigLoader()); if (mergedConfig.hasLocations() && mergedConfig.hasClasses()) { throw new IllegalStateException(String.format( "Neither %s nor %s supports loading an ApplicationContext from %s: " + "declare either 'locations' or 'classes' but not both.", name(getXmlLoader()), name(getAnnotationConfigLoader()), mergedConfig)); } for (SmartContextLoader loader : candidates) { // Determine if each loader can load a context from the mergedConfig. If it // can, let it; otherwise, keep iterating. if (supports(loader, mergedConfig)) { return delegateLoading(loader, mergedConfig); } } // If neither of the candidates supports the mergedConfig based on resources but // ACIs were declared, then delegate to the annotation config loader. if (!mergedConfig.getContextInitializerClasses().isEmpty()) { return delegateLoading(getAnnotationConfigLoader(), mergedConfig); } // else... throw new IllegalStateException(String.format( "Neither %s nor %s was able to load an ApplicationContext from %s.", name(getXmlLoader()), name(getAnnotationConfigLoader()), mergedConfig)); }
private boolean supports(SmartContextLoader loader, MergedContextConfiguration mergedConfig) { if (loader == getAnnotationConfigLoader()) { return ObjectUtils.isEmpty(mergedConfig.getLocations()) && !ObjectUtils.isEmpty(mergedConfig.getClasses()); } else { return !ObjectUtils.isEmpty(mergedConfig.getLocations()) && ObjectUtils.isEmpty(mergedConfig.getClasses()); } }
@Override protected SmartContextLoader getXmlLoader() { return this.xmlLoader; }
@Override protected SmartContextLoader getAnnotationConfigLoader() { return this.annotationConfigLoader; }
private static String name(SmartContextLoader loader) { return loader.getClass().getSimpleName(); }
/** * Build the {@link MergedContextConfiguration merged context configuration} * for the supplied {@link Class testClass}, context configuration attributes, * and parent context configuration. * @param testClass the test class for which the {@code MergedContextConfiguration} * should be built (must not be {@code null}) * @param configAttributesList the list of context configuration attributes for the * specified test class, ordered <em>bottom-up</em> (i.e., as if we were * traversing up the class hierarchy); never {@code null} or empty * @param parentConfig the merged context configuration for the parent application * context in a context hierarchy, or {@code null} if there is no parent * @param cacheAwareContextLoaderDelegate the cache-aware context loader delegate to * be passed to the {@code MergedContextConfiguration} constructor * @return the merged context configuration * @see #resolveContextLoader * @see ContextLoaderUtils#resolveContextConfigurationAttributes * @see SmartContextLoader#processContextConfiguration * @see ContextLoader#processLocations * @see ActiveProfilesUtils#resolveActiveProfiles * @see ApplicationContextInitializerUtils#resolveInitializerClasses * @see MergedContextConfiguration */ private MergedContextConfiguration buildMergedContextConfiguration(Class<?> testClass, List<ContextConfigurationAttributes> configAttributesList, MergedContextConfiguration parentConfig, CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate) { 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); locationsList.addAll(0, Arrays.asList(configAttributes.getLocations())); classesList.addAll(0, Arrays.asList(configAttributes.getClasses())); } else { String[] processedLocations = contextLoader.processLocations(configAttributes.getDeclaringClass(), configAttributes.getLocations()); locationsList.addAll(0, Arrays.asList(processedLocations)); // Legacy ContextLoaders don't know how to process classes } if (!configAttributes.isInheritLocations()) { break; } } String[] locations = StringUtils.toStringArray(locationsList); Class<?>[] classes = ClassUtils.toClassArray(classesList); Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> initializerClasses = // ApplicationContextInitializerUtils.resolveInitializerClasses(configAttributesList); String[] activeProfiles = ActiveProfilesUtils.resolveActiveProfiles(testClass); MergedTestPropertySources mergedTestPropertySources = TestPropertySourceUtils.buildMergedTestPropertySources(testClass); MergedContextConfiguration mergedConfig = new MergedContextConfiguration(testClass, locations, classes, initializerClasses, activeProfiles, mergedTestPropertySources.getLocations(), mergedTestPropertySources.getProperties(), contextLoader, cacheAwareContextLoaderDelegate, parentConfig); return processMergedContextConfiguration(mergedConfig); }
protected SmartContextLoader getXmlLoader() { return this.xmlLoader; }
protected SmartContextLoader getAnnotationConfigLoader() { return this.annotationConfigLoader; }
/** * Get the delegate {@code SmartContextLoader} that supports XML configuration * files and/or Groovy scripts. */ protected abstract SmartContextLoader getXmlLoader();
/** * Get the delegate {@code SmartContextLoader} that supports annotated classes. */ protected abstract SmartContextLoader getAnnotationConfigLoader();
/** * Get the delegate {@code SmartContextLoader} that supports XML configuration files. */ protected abstract SmartContextLoader getXmlLoader();