diff --git a/build-spring-framework/resources/changelog.txt b/build-spring-framework/resources/changelog.txt index 4e6e1c0e3f3..aa6c5e0a6e7 100644 --- a/build-spring-framework/resources/changelog.txt +++ b/build-spring-framework/resources/changelog.txt @@ -9,6 +9,8 @@ Changes in version 3.0.0.RC2 (2009-10-30) * updated to final versions of JSR-330 "javax.inject" and JSR-303 "javax.validation" APIs * full compliance with the JSR-330 TCK (i.e. full compliance with the final specification) * support for Hibernate Validator 4.0 GA (as the JSR-303 reference implementation) +* added AnnotatedBeanDefinitionReader helper for programmatic registration of annotated classes +* added AnnotationConfig(Web)ApplicationContext for convenient registration/scanning of classes * revised MethodParameter's annotation accessor methods * PathMatchingResourcePatternResolver leniently ignores non-existing root directories * DefaultConversionService understands "on"/"off", "yes"/"no", "1"/"0" as boolean values @@ -21,6 +23,7 @@ Changes in version 3.0.0.RC2 (2009-10-30) * ContentNegotiatingViewResolver works with ignoreAcceptHeader and defaultContentType as well * re-introduced Struts 1.x support ("org.springframework.web.struts") in deprecated form * deprecated scheduling support for JDK 1.3 Timer ("org.springframework.scheduling.timer") +* deprecated remoting support for JAX-RPC (in favor of JAX-WS) Changes in version 3.0.0.RC1 (2009-09-25) diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index 18609d8858b..ef09f866762 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -243,6 +243,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto //--------------------------------------------------------------------- public T getBean(Class requiredType) throws BeansException { + Assert.notNull(requiredType, "Required type must not be null"); String[] beanNames = getBeanNamesForType(requiredType); if (beanNames.length == 1) { return getBean(beanNames[0], requiredType); @@ -251,7 +252,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto return getParentBeanFactory().getBean(requiredType); } else { - throw new NoSuchBeanDefinitionException(requiredType, "expected single bean but found " + beanNames.length); + throw new NoSuchBeanDefinitionException(requiredType, "expected single bean but found " + + beanNames.length + ": " + StringUtils.arrayToCommaDelimitedString(beanNames)); } } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java index 6cbc488bdc4..3d8c76137bc 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java @@ -27,10 +27,12 @@ import org.springframework.beans.factory.support.BeanNameGenerator; /** * Convenient adapter for programmatic registration of annotated bean classes. - * + * This is an alternative to {@link ClassPathBeanDefinitionScanner}, applying + * the same resolution of annotations but for explicitly registered classes only. * * @author Juergen Hoeller * @since 3.0 + * @see AnnotationConfigApplicationContext#register */ public class AnnotatedBeanDefinitionReader { @@ -40,11 +42,15 @@ public class AnnotatedBeanDefinitionReader { private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver(); - private boolean includeAnnotationConfig = true; - + /** + * Create a new AnnotatedBeanDefinitionReader for the given bean factory. + * @param registry the BeanFactory to load bean definitions into, + * in the form of a BeanDefinitionRegistry + */ public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) { this.registry = registry; + AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } @@ -65,35 +71,14 @@ public class AnnotatedBeanDefinitionReader { /** * Set the ScopeMetadataResolver to use for detected bean classes. - * Note that this will override any custom "scopedProxyMode" setting. *

The default is an {@link AnnotationScopeMetadataResolver}. - * @see #setScopedProxyMode */ public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) { - this.scopeMetadataResolver = scopeMetadataResolver; - } - - /** - * Specify the proxy behavior for non-singleton scoped beans. - * Note that this will override any custom "scopeMetadataResolver" setting. - *

The default is {@link ScopedProxyMode#NO}. - * @see #setScopeMetadataResolver - */ - public void setScopedProxyMode(ScopedProxyMode scopedProxyMode) { - this.scopeMetadataResolver = new AnnotationScopeMetadataResolver(scopedProxyMode); - } - - /** - * Specify whether to register annotation config post-processors. - *

The default is to register the post-processors. Turn this off - * to be able to ignore the annotations or to process them differently. - */ - public void setIncludeAnnotationConfig(boolean includeAnnotationConfig) { - this.includeAnnotationConfig = includeAnnotationConfig; + this.scopeMetadataResolver = (scopeMetadataResolver != null ? scopeMetadataResolver : new AnnotationScopeMetadataResolver()); } - public void registerBeans(Class... annotatedClasses) { + public void register(Class... annotatedClasses) { for (Class annotatedClass : annotatedClasses) { registerBean(annotatedClass); } @@ -112,17 +97,7 @@ public class AnnotatedBeanDefinitionReader { ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); - if (abd.getMetadata().isAnnotated(Primary.class.getName())) { - abd.setPrimary(true); - } - if (abd.getMetadata().isAnnotated(Lazy.class.getName())) { - Boolean value = (Boolean) abd.getMetadata().getAnnotationAttributes(Lazy.class.getName()).get("value"); - abd.setLazyInit(value); - } - if (abd.getMetadata().isAnnotated(DependsOn.class.getName())) { - String[] value = (String[]) abd.getMetadata().getAnnotationAttributes(DependsOn.class.getName()).get("value"); - abd.setDependsOn(value); - } + AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers != null) { for (Class qualifier : qualifiers) { if (Primary.class.equals(qualifier)) { @@ -137,28 +112,8 @@ public class AnnotatedBeanDefinitionReader { } } BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); - definitionHolder = applyScopedProxyMode(definitionHolder, scopeMetadata); + definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); - - // Register annotation config processors, if necessary. - if (this.includeAnnotationConfig) { - AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); - } - } - - /** - * Apply the specified scope to the given bean definition. - * @param definition the bean definition to configure - * @param metadata the corresponding scope metadata - * @return the final bean definition to use (potentially a proxy) - */ - private BeanDefinitionHolder applyScopedProxyMode(BeanDefinitionHolder definition, ScopeMetadata metadata) { - ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode(); - if (scopedProxyMode.equals(ScopedProxyMode.NO)) { - return definition; - } - boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS); - return ScopedProxyCreator.createScopedProxy(definition, this.registry, proxyTargetClass); } } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java new file mode 100644 index 00000000000..8ee35b30635 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java @@ -0,0 +1,123 @@ +/* + * Copyright 2002-2009 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.context.support.GenericApplicationContext; + +/** + * Standalone application context, accepting annotated classes as input - in particular + * {@link org.springframework.context.annotation.Configuration @Configuration}-annotated + * classes, but also plain {@link org.springframework.stereotype.Component @Components} + * and JSR-330 compliant classes using {@literal javax.inject} annotations. Allows for + * registering classes one by one ({@link #register}) as well as for classpath scanning + * ({@link #scan}). + * + *

Useful for test harnesses or any other scenario where XML-based configuration + * is unnecessary or undesired. + * + *

In case of multiple Configuration classes, {@link Bean} methods defined in later + * classes will override those defined in earlier classes. This can be leveraged to + * deliberately override certain bean definitions via an extra Configuration class. + * + * @author Chris Beams + * @author Juergen Hoeller + * @since 3.0 + * @see AnnotatedBeanDefinitionReader + * @see ClassPathBeanDefinitionScanner + */ +public class AnnotationConfigApplicationContext extends GenericApplicationContext { + + private final AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(this); + + private final ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this); + + + /** + * Create a new AnnotationConfigApplicationContext that needs to be populated + * through {@link #add} calls and then manually {@link #refresh refreshed}. + */ + public AnnotationConfigApplicationContext() { + } + + /** + * Create a new AnnotationConfigApplicationContext, deriving bean + * definitions from the given annotated classes and automatically + * refreshing the context. + * @param annotatedClasses one or more annotated classes, + * e.g. {@link Configuration @Configuration} classes + */ + public AnnotationConfigApplicationContext(Class... annotatedClasses) { + register(annotatedClasses); + refresh(); + } + + /** + * Create a new AnnotationConfigApplicationContext, scanning for bean + * definitions in the given packages and automatically refreshing the + * context. + * @param basePackages the packages to check for annotated classes + */ + public AnnotationConfigApplicationContext(String... basePackages) { + scan(basePackages); + refresh(); + } + + + /** + * Set the BeanNameGenerator to use for detected bean classes. + *

Default is a {@link AnnotationBeanNameGenerator}. + */ + public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) { + this.reader.setBeanNameGenerator(beanNameGenerator); + this.scanner.setBeanNameGenerator(beanNameGenerator); + } + + /** + * Set the ScopeMetadataResolver to use for detected bean classes. + *

The default is an {@link AnnotationScopeMetadataResolver}. + */ + public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) { + this.reader.setScopeMetadataResolver(scopeMetadataResolver); + this.scanner.setScopeMetadataResolver(scopeMetadataResolver); + } + + + /** + * Register an annotated class to be processed. Allows for programmatically + * building a {@link AnnotationConfigApplicationContext}. Note that + * {@link AnnotationConfigApplicationContext#refresh()} must be called in + * order for the context to fully process the new class. + *

Calls to {@link #register} are idempotent; adding the same + * annotated class more than once has no additional effect. + * @param annotatedClasses one or more annotated classes, + * e.g. {@link Configuration @Configuration} classes + * @see #refresh() + */ + public void register(Class... annotatedClasses) { + this.reader.register(annotatedClasses); + } + + /** + * Perform a scan within the specified base packages. + * @param basePackages the packages to check for annotated classes + */ + public void scan(String[] basePackages) { + this.scanner.scan(basePackages); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java index 78ebc9c1373..db2801e1c36 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java @@ -19,6 +19,7 @@ package org.springframework.context.annotation; import java.util.LinkedHashSet; import java.util.Set; +import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor; import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor; import org.springframework.beans.factory.config.BeanDefinition; @@ -160,4 +161,29 @@ public class AnnotationConfigUtils { return new BeanDefinitionHolder(definition, beanName); } + static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) { + if (abd.getMetadata().isAnnotated(Primary.class.getName())) { + abd.setPrimary(true); + } + if (abd.getMetadata().isAnnotated(Lazy.class.getName())) { + Boolean value = (Boolean) abd.getMetadata().getAnnotationAttributes(Lazy.class.getName()).get("value"); + abd.setLazyInit(value); + } + if (abd.getMetadata().isAnnotated(DependsOn.class.getName())) { + String[] value = (String[]) abd.getMetadata().getAnnotationAttributes(DependsOn.class.getName()).get("value"); + abd.setDependsOn(value); + } + } + + static BeanDefinitionHolder applyScopedProxyMode( + ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) { + + ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode(); + if (scopedProxyMode.equals(ScopedProxyMode.NO)) { + return definition; + } + boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS); + return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass); + } + } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java index 28b38c633ba..0c4019d9728 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java @@ -46,6 +46,7 @@ import org.springframework.util.PatternMatchUtils; * @author Mark Fisher * @author Juergen Hoeller * @since 2.5 + * @see AnnotationConfigApplicationContext#scan * @see org.springframework.stereotype.Component * @see org.springframework.stereotype.Repository * @see org.springframework.stereotype.Service @@ -145,7 +146,7 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo * @see #setScopedProxyMode */ public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) { - this.scopeMetadataResolver = scopeMetadataResolver; + this.scopeMetadataResolver = (scopeMetadataResolver != null ? scopeMetadataResolver : new AnnotationScopeMetadataResolver()); } /** @@ -206,22 +207,11 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { - AnnotatedBeanDefinition abd = (AnnotatedBeanDefinition) candidate; - if (abd.getMetadata().isAnnotated(Primary.class.getName())) { - abd.setPrimary(true); - } - if (abd.getMetadata().isAnnotated(Lazy.class.getName())) { - Boolean value = (Boolean) abd.getMetadata().getAnnotationAttributes(Lazy.class.getName()).get("value"); - abd.setLazyInit(value); - } - if (abd.getMetadata().isAnnotated(DependsOn.class.getName())) { - String[] value = (String[]) abd.getMetadata().getAnnotationAttributes(DependsOn.class.getName()).get("value"); - abd.setDependsOn(value); - } + AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } if (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); - definitionHolder = applyScopedProxyMode(definitionHolder, scopeMetadata); + definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); registerBeanDefinition(definitionHolder, this.registry); } @@ -300,19 +290,4 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo newDefinition.equals(existingDefinition)); // scanned equivalent class twice } - /** - * Apply the specified scope to the given bean definition. - * @param definition the bean definition to configure - * @param metadata the corresponding scope metadata - * @return the final bean definition to use (potentially a proxy) - */ - private BeanDefinitionHolder applyScopedProxyMode(BeanDefinitionHolder definition, ScopeMetadata metadata) { - ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode(); - if (scopedProxyMode.equals(ScopedProxyMode.NO)) { - return definition; - } - boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS); - return ScopedProxyCreator.createScopedProxy(definition, this.registry, proxyTargetClass); - } - } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/Configuration.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/Configuration.java index fe38ac92f9b..0cd221faef0 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/Configuration.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/Configuration.java @@ -56,7 +56,7 @@ import org.springframework.stereotype.Component; * @see Lazy * @see Bean * @see ConfigurationClassPostProcessor; - * @see ConfigurationClassApplicationContext; + * @see AnnotationConfigApplicationContext ; */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @@ -70,7 +70,7 @@ public @interface Configuration { * a bean name will be automatically generated. * *

The custom name applies only if the Configuration class is picked up via - * component scanning or supplied directly to a {@link ConfigurationClassApplicationContext}. + * component scanning or supplied directly to a {@link AnnotationConfigApplicationContext}. * If the Configuration class is registered as a traditional XML bean definition, * the name/id of the bean element will take precedence. * diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassApplicationContext.java deleted file mode 100644 index 7e6b7e2714a..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassApplicationContext.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright 2002-2009 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.annotation; - -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - -import org.springframework.beans.factory.ListableBeanFactory; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.support.DefaultBeanNameGenerator; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.context.support.AbstractRefreshableApplicationContext; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - - -/** - * Standalone application context, accepting {@link Configuration @Configuration} - * -annotated class literals as input. Useful for test harnesses or any other scenario - * where XML-based configuration is unnecessary or undesired. - * - *

In case of multiple Configuration classes, {@link Bean} - * methods defined in later classes will override those defined in earlier - * classes. This can be leveraged to deliberately override certain bean - * definitions via an extra Configuration class. - * - * @author Chris Beams - * @since 3.0 - * @see Configuration - */ -public class ConfigurationClassApplicationContext extends AbstractRefreshableApplicationContext { - - private final ConfigurationClassApplicationContext.Delegate delegate = - new ConfigurationClassApplicationContext.Delegate(); - - /** - * Create a new {@link ConfigurationClassApplicationContext}, loading bean - * definitions from the given {@literal configClasses} and automatically - * refreshing the context.

Note: if zero classes are specified, the - * context will not be refreshed automatically, assuming that - * the user will subsequently call {@link #addConfigurationClass(Class)} - * and then manually refresh. - * - * @param configClasses zero or more {@link Configuration} classes - * @see #addConfigurationClass(Class) - * @see #refresh() - */ - public ConfigurationClassApplicationContext(Class... configClasses) { - if (configClasses.length == 0) { - return; - } - - for (Class configClass : configClasses) { - this.addConfigurationClass(configClass); - } - - this.refresh(); - } - - /** - * Add a {@link Configuration} class to be processed. Allows for programmatically - * building a {@link ConfigurationClassApplicationContext}. Note that - * {@link ConfigurationClassApplicationContext#refresh()} must be called in - * order for the context to process the new class. Calls to - * {@link #addConfigurationClass(Class)} are idempotent; adding the same - * Configuration class more than once has no additional effect. - * @param configClass new Configuration class to be processed. - * @see #ConfigurationClassApplicationContext(Class...) - * @see #refresh() - */ - public void addConfigurationClass(Class configClass) { - this.delegate.addConfigurationClass(configClass); - } - - /** - * Register a {@link BeanDefinition} for each {@link Configuration @Configuration} - * class specified. Enables the default set of annotation configuration post - * processors, such that {@literal @Autowired}, {@literal @Required}, and associated - * annotations can be used within Configuration classes. - * - *

Configuration class bean definitions are registered with generated bean definition - * names unless the {@literal value} attribute is provided to the Configuration annotation. - * - * @see AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry) - * @see ConfigurationClassPostProcessor - * @see DefaultBeanNameGenerator - * @see Configuration#value() - */ - @Override - protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) { - this.delegate.loadBeanDefinitions(beanFactory); - } - - /** - * Return the bean instance that matches the given object type. - * - * @param - * @param requiredType type the bean must match; can be an interface or superclass. - * {@literal null} is disallowed. - * @return bean matching required type - * @throws NoSuchBeanDefinitionException if there is not exactly one matching bean - * found - * @see org.springframework.beans.factory.ListableBeanFactory#getBeansOfType(Class) - * @see org.springframework.beans.factory.BeanFactory#getBean(String, Class) - */ - public T getBean(Class requiredType) { - return this.delegate.getBean(requiredType, this); - } - - - /** - * Encapsulates behavior common to {@link ConfigurationClassApplicationContext} - * and its {@link org.springframework.web.context.support.ConfigurationClassWebApplicationContext} - * variant. Both classes already participate in mutually exclusive superclass - * hierarchies, and this class allows for avoiding what would otherwise be a multiple - * inheritance problem through composition. - * - *

This class is public by necessity but should be considered private and - * subject to change without notice. - */ - public static class Delegate { - - private final Set> configClasses = new LinkedHashSet>(); - - /** - * @see ConfigurationClassApplicationContext#addConfigurationClass(Class) - */ - public void addConfigurationClass(Class configClass) { - Assert.notNull( - AnnotationUtils.findAnnotation(configClass, Configuration.class), - "Class [" + configClass.getName() + "] is not annotated with @Configuration"); - this.configClasses.add(configClass); - } - - /** - * @see ConfigurationClassApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory) - */ - public void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) { - // @Autowired and friends must be enabled by default when processing @Configuration classes - AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory); - - for (Class configClass : this.configClasses) { - RootBeanDefinition def = new RootBeanDefinition(configClass); - String name = AnnotationUtils.findAnnotation(configClass, Configuration.class).value(); - if (!StringUtils.hasLength(name)) { - name = new DefaultBeanNameGenerator().generateBeanName(def, beanFactory); - } - beanFactory.registerBeanDefinition(name, def); - } - } - - /** - * @see ConfigurationClassApplicationContext#getBean(Class) - */ - public T getBean(Class requiredType, ListableBeanFactory context) { - Assert.notNull(requiredType, "requiredType may not be null"); - Assert.notNull(context, "context may not be null"); - Map beansOfType = context.getBeansOfType(requiredType); - switch (beansOfType.size()) { - case 0: - throw new NoSuchBeanDefinitionException(requiredType); - case 1: - return beansOfType.values().iterator().next(); - default: - throw new NoSuchBeanDefinitionException(requiredType, - beansOfType.size() + " matching bean definitions found " + - "(" + StringUtils.collectionToCommaDelimitedString(beansOfType.keySet()) + "). " + - "Consider qualifying with getBean(Class beanType, String beanName) or " + - "declaring one bean definition as @Primary"); - } - } - } - -} diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractRefreshableApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractRefreshableApplicationContext.java index 805923c67fc..e0a02ec70b8 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractRefreshableApplicationContext.java +++ b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractRefreshableApplicationContext.java @@ -49,7 +49,7 @@ import org.springframework.core.LocalVariableTableParameterNameDiscoverer; * specific bean definition format, are {@link ClassPathXmlApplicationContext} * and {@link FileSystemXmlApplicationContext}, which both derive from the * common {@link AbstractXmlApplicationContext} base class; - * {@link org.springframework.context.annotation.ConfigurationClassApplicationContext} + * {@link org.springframework.context.annotation.AnnotationConfigApplicationContext} * supports {@literal @Configuration}-annotated classes as a source of bean definitions. * * @author Juergen Hoeller @@ -60,7 +60,7 @@ import org.springframework.core.LocalVariableTableParameterNameDiscoverer; * @see AbstractXmlApplicationContext * @see ClassPathXmlApplicationContext * @see FileSystemXmlApplicationContext - * @see org.springframework.context.annotation.ConfigurationClassApplicationContext + * @see org.springframework.context.annotation.AnnotationConfigApplicationContext */ public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext { @@ -223,12 +223,12 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl * Load bean definitions into the given bean factory, typically through * delegating to one or more bean definition readers. * @param beanFactory the bean factory to load bean definitions into - * @throws IOException if loading of bean definition files failed * @throws BeansException if parsing of the bean definitions failed + * @throws IOException if loading of bean definition files failed * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader */ protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) - throws IOException, BeansException; + throws BeansException, IOException; } diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractXmlApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractXmlApplicationContext.java index f81e278685c..853cad3b59c 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractXmlApplicationContext.java +++ b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractXmlApplicationContext.java @@ -66,7 +66,7 @@ public abstract class AbstractXmlApplicationContext extends AbstractRefreshableC * @see #loadBeanDefinitions */ @Override - protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { + protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/ConfigurationClassApplicationContextTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/ConfigurationClassApplicationContextTests.java index 6278ce6eeed..6f15b00d6cc 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/ConfigurationClassApplicationContextTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/ConfigurationClassApplicationContextTests.java @@ -19,65 +19,36 @@ package org.springframework.context.annotation; import static java.lang.String.format; import static org.hamcrest.CoreMatchers.*; -import static org.junit.matchers.JUnitMatchers.*; import static org.junit.Assert.*; - import org.junit.Test; +import static org.junit.matchers.JUnitMatchers.*; + import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; +/** + * @author Chris Beams + */ public class ConfigurationClassApplicationContextTests { - @Test(expected=IllegalStateException.class) - public void emptyConstructorRequiresManualRefresh() { - ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext(); - context.getBean("foo"); - } - - @Test - public void classesMissingConfigurationAnnotationAddedToContextAreDisallowed() { - ConfigurationClassApplicationContext ctx = - new ConfigurationClassApplicationContext(Config.class); - - // should be fine - ctx.addConfigurationClass(ConfigWithCustomName.class); - - // should cause immediate failure (no refresh necessary) - try { - ctx.addConfigurationClass(ConfigMissingAnnotation.class); - fail("expected exception"); - } catch (IllegalArgumentException ex) { - assertThat(ex.getMessage(), - equalTo("Class [" + ConfigMissingAnnotation.class.getName() + "] " + - "is not annotated with @Configuration")); - } - } - - @Test(expected=IllegalArgumentException.class) - public void classesMissingConfigurationAnnotationSuppliedToConstructorAreDisallowed() { - new ConfigurationClassApplicationContext(ConfigMissingAnnotation.class); - } - @Test(expected=IllegalArgumentException.class) public void nullGetBeanParameterIsDisallowed() { - ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext(Config.class); + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class); context.getBean((Class)null); } @Test public void addConfigurationClass() { - ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext(); - context.addConfigurationClass(Config.class); + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(Config.class, NameConfig.class); context.refresh(); context.getBean("testBean"); - context.addConfigurationClass(NameConfig.class); - context.refresh(); context.getBean("name"); } @Test public void getBeanByType() { - ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext(Config.class); + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class); TestBean testBean = context.getBean(TestBean.class); assertNotNull("getBean() should not return null", testBean); assertThat(testBean.name, equalTo("foo")); @@ -89,10 +60,10 @@ public class ConfigurationClassApplicationContextTests { */ @Test public void defaultConfigClassBeanNameIsGeneratedProperly() { - ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext(Config.class); + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class); // attempt to retrieve the instance by its generated bean name - Config configObject = (Config) context.getBean(Config.class.getName() + "#0"); + Config configObject = (Config) context.getBean("configurationClassApplicationContextTests.Config"); assertNotNull(configObject); } @@ -102,8 +73,8 @@ public class ConfigurationClassApplicationContextTests { */ @Test public void explicitConfigClassBeanNameIsRespected() { - ConfigurationClassApplicationContext context = - new ConfigurationClassApplicationContext(ConfigWithCustomName.class); + AnnotationConfigApplicationContext context = + new AnnotationConfigApplicationContext(ConfigWithCustomName.class); // attempt to retrieve the instance by its specified name ConfigWithCustomName configObject = @@ -113,7 +84,7 @@ public class ConfigurationClassApplicationContextTests { @Test public void getBeanByTypeRaisesNoSuchBeanDefinitionException() { - ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext(Config.class); + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class); // attempt to retrieve a bean that does not exist Class targetType = java.util.regex.Pattern.class; @@ -121,7 +92,7 @@ public class ConfigurationClassApplicationContextTests { Object bean = context.getBean(targetType); fail("should have thrown NoSuchBeanDefinitionException, instead got: " + bean); } catch (NoSuchBeanDefinitionException ex) { - assertThat(ex.getMessage(), equalTo( + assertThat(ex.getMessage(), containsString( format("No unique bean of type [%s] is defined", targetType.getName()))); } } @@ -129,7 +100,7 @@ public class ConfigurationClassApplicationContextTests { @SuppressWarnings("unchecked") @Test public void getBeanByTypeAmbiguityRaisesException() { - ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext(TwoTestBeanConfig.class); + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TwoTestBeanConfig.class); try { context.getBean(TestBean.class); @@ -137,10 +108,8 @@ public class ConfigurationClassApplicationContextTests { assertThat(ex.getMessage(), allOf( containsString("No unique bean of type [" + TestBean.class.getName() + "] is defined"), - containsString("2 matching bean definitions found"), containsString("tb1"), - containsString("tb2"), - containsString("Consider qualifying with") + containsString("tb2") ) ); } @@ -148,7 +117,7 @@ public class ConfigurationClassApplicationContextTests { @Test public void autowiringIsEnabledByDefault() { - ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext(AutowiredConfig.class); + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutowiredConfig.class); assertThat(context.getBean(TestBean.class).name, equalTo("foo")); } diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/XmlPortletApplicationContext.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/XmlPortletApplicationContext.java index 6ddb030edb6..6cb6e91f287 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/XmlPortletApplicationContext.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/XmlPortletApplicationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2009 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. @@ -77,7 +77,7 @@ public class XmlPortletApplicationContext extends AbstractRefreshablePortletAppl * @see #loadBeanDefinitions */ @Override - protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { + protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java b/org.springframework.web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java new file mode 100644 index 00000000000..efa1afdd6f6 --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java @@ -0,0 +1,136 @@ +/* + * Copyright 2002-2009 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.support; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; +import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; +import org.springframework.context.annotation.ScopeMetadataResolver; + +/** + * {@link org.springframework.web.context.WebApplicationContext} implementation + * which accepts annotated classes as input - in particular + * {@link org.springframework.context.annotation.Configuration @Configuration}-annotated + * classes, but also plain {@link org.springframework.stereotype.Component @Components} + * and JSR-330 compliant classes using {@literal javax.inject} annotations. Allows for + * registering classes one by one (specifying class names as config location) as well + * as for classpath scanning (specifying base packages as config location). + * + *

This is essentially the equivalent of + * {@link org.springframework.context.annotation.AnnotationConfigApplicationContext} + * for a web environment. + * + *

To make use of this application context, the "contextClass" context-param for + * ContextLoader and/or "contextClass" init-param for FrameworkServlet must be set to + * the fully-qualified name of this class. + * + *

Unlike {@link XmlWebApplicationContext}, no default configuration class locations + * are assumed. Rather, it is a requirement to set the "contextConfigLocation" + * context-param for ContextLoader and/or "contextConfigLocation" init-param for + * FrameworkServlet. + * + *

Note: In case of multiple {@literal @Configuration} classes, later {@literal @Bean} + * definitions will override ones defined in earlier loaded files. This can be leveraged + * to deliberately override certain bean definitions via an extra Configuration class. + * + * @author Chris Beams + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.context.annotation.AnnotationConfigApplicationContext + */ +public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext { + + /** + * Register a {@link BeanDefinition} for each class specified by {@link #getConfigLocations()}, + * or scan each specified package for annotated classes. Enables the default set of + * annotation configuration post processors, such that {@literal @Autowired}, + * {@literal @Required}, and associated annotations can be used. + *

Configuration class bean definitions are registered with generated bean definition + * names unless the {@literal value} attribute is provided to the stereotype annotation. + * @see #getConfigLocations() + * @see AnnotatedBeanDefinitionReader + * @see ClassPathBeanDefinitionScanner + */ + @Override + protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) { + AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(beanFactory); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory); + BeanNameGenerator beanNameGenerator = getBeanNameGenerator(); + ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver(); + if (beanNameGenerator != null) { + reader.setBeanNameGenerator(beanNameGenerator); + scanner.setBeanNameGenerator(beanNameGenerator); + } + if (scopeMetadataResolver != null) { + reader.setScopeMetadataResolver(scopeMetadataResolver); + scanner.setScopeMetadataResolver(scopeMetadataResolver); + } + + String[] configLocations = getConfigLocations(); + if (configLocations != null) { + for (String configLocation : configLocations) { + try { + Class clazz = getClassLoader().loadClass(configLocation); + if (logger.isInfoEnabled()) { + logger.info("Successfully resolved class for [" + configLocation + "]"); + } + reader.register(clazz); + } + catch (ClassNotFoundException ex) { + if (logger.isDebugEnabled()) { + logger.debug("Could not load class for config location [" + configLocation + + "] - trying package scan. " + ex); + } + int count = scanner.scan(configLocation); + if (logger.isInfoEnabled()) { + if (count == 0) { + logger.info("No annotated classes found for specified class/package [" + configLocation + "]"); + } + else { + logger.info("Found " + count + " annotated classes in package [" + configLocation + "]"); + } + } + } + } + } + } + + /** + * Provide a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader} + * and/or {@link ClassPathBeanDefinitionScanner}, if any. + *

Default is {@link org.springframework.context.annotation.AnnotationBeanNameGenerator}. + * @see AnnotatedBeanDefinitionReader#setBeanNameGenerator + * @see ClassPathBeanDefinitionScanner#setBeanNameGenerator + */ + protected BeanNameGenerator getBeanNameGenerator() { + return null; + } + + /** + * Provide a custom {@link ScopeMetadataResolver} for use with {@link AnnotatedBeanDefinitionReader} + * and/or {@link ClassPathBeanDefinitionScanner}, if any. + *

Default is {@link org.springframework.context.annotation.AnnotationScopeMetadataResolver}. + * @see AnnotatedBeanDefinitionReader#setScopeMetadataResolver + * @see ClassPathBeanDefinitionScanner#setScopeMetadataResolver + */ + protected ScopeMetadataResolver getScopeMetadataResolver() { + return null; + } + +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/support/ConfigurationClassWebApplicationContext.java b/org.springframework.web/src/main/java/org/springframework/web/context/support/ConfigurationClassWebApplicationContext.java deleted file mode 100644 index 24763a11cac..00000000000 --- a/org.springframework.web/src/main/java/org/springframework/web/context/support/ConfigurationClassWebApplicationContext.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2002-2009 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.context.support; - -import java.io.IOException; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.support.DefaultBeanNameGenerator; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.context.annotation.AnnotationConfigUtils; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ConfigurationClassApplicationContext; -import org.springframework.context.annotation.ConfigurationClassPostProcessor; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; - - -/** - * {@link org.springframework.web.context.WebApplicationContext} implementation - * which takes its configuration from {@link Configuration @Configuration} classes. - * This is essentially the equivalent of - * {@link org.springframework.context.annotation.ConfigurationClassApplicationContext} - * for a web environment. - * - *

To make use of this application context, the "contextClass" context-param for - * ContextLoader and/or "contextClass" init-param for FrameworkServlet must be set to - * the fully-qualified name of this class. - * - *

Unlike {@link XmlWebApplicationContext}, no default configuration class locations - * are assumed. Rather, it is a requirement to set the "contextConfigLocation" - * context-param for ContextLoader and/or "contextConfigLocation" init-param for - * FrameworkServlet. If these params are not set, an IllegalArgumentException will be thrown. - * - *

Note: In case of multiple {@literal @Configuration} classes, later {@literal @Bean} - * definitions will override ones defined in earlier loaded files. This can be leveraged - * to deliberately override certain bean definitions via an extra Configuration class. - * - * @author Chris Beams - * @since 3.0 - * @see ConfigurationClassApplicationContext - * @see ConfigurationClassApplicationContext.Delegate - */ -public class ConfigurationClassWebApplicationContext extends AbstractRefreshableWebApplicationContext { - - private final ConfigurationClassApplicationContext.Delegate delegate = - new ConfigurationClassApplicationContext.Delegate(); - - /** - * Register a {@link BeanDefinition} for each {@link Configuration @Configuration} - * class specified by {@link #getConfigLocations()}. Enables the default set of - * annotation configuration post processors, such that {@literal @Autowired}, - * {@literal @Required}, and associated annotations can be used within Configuration - * classes. - * - *

Configuration class bean definitions are registered with generated bean - * definition names unless the {@literal value} attribute is provided to the - * Configuration annotation. - * - * @throws IllegalArgumentException if configLocations array is null or empty - * @throws IOException if any one configLocation is not loadable as a class - * @throws IllegalArgumentException if any one loaded class is not annotated with {@literal @Configuration} - * @see #getConfigLocations() - * @see AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry) - * @see ConfigurationClassPostProcessor - * @see DefaultBeanNameGenerator - * @see Configuration#value() - */ - @Override - protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) - throws IOException, BeansException { - - Assert.notEmpty(getConfigLocations(), - "No config locations were specified. Is the 'contextConfigLocations' " + - "context-param and/or init-param set properly in web.xml?"); - - for (String configLocation : getConfigLocations()) { - try { - Class configClass = ClassUtils.getDefaultClassLoader().loadClass(configLocation); - this.delegate.addConfigurationClass(configClass); - } catch (ClassNotFoundException ex) { - throw new IOException("Could not load @Configuration class [" + configLocation + "]", ex); - } - } - - this.delegate.loadBeanDefinitions(beanFactory); - } - - /** - * Return the bean instance that matches the given object type. - * - * @param - * @param requiredType type the bean must match; can be an interface or superclass. - * {@literal null} is disallowed. - * @return bean matching required type - * @throws NoSuchBeanDefinitionException if there is not exactly one matching bean - * found - * @see org.springframework.beans.factory.ListableBeanFactory#getBeansOfType(Class) - * @see org.springframework.beans.factory.BeanFactory#getBean(String, Class) - */ - public T getBean(Class requiredType) { - return this.delegate.getBean(requiredType, this); - } -} diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/support/XmlWebApplicationContext.java b/org.springframework.web/src/main/java/org/springframework/web/context/support/XmlWebApplicationContext.java index e09995db670..0290cb668a8 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/support/XmlWebApplicationContext.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/support/XmlWebApplicationContext.java @@ -78,7 +78,7 @@ public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationC * @see #loadBeanDefinitions */ @Override - protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { + protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); @@ -111,14 +111,13 @@ public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationC * therefore this method is just supposed to load and/or register bean definitions. *

Delegates to a ResourcePatternResolver for resolving location patterns * into Resource instances. - * @throws org.springframework.beans.BeansException in case of bean registration errors * @throws java.io.IOException if the required XML document isn't found * @see #refreshBeanFactory * @see #getConfigLocations * @see #getResources * @see #getResourcePatternResolver */ - protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { + protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException { String[] configLocations = getConfigLocations(); if (configLocations != null) { for (String configLocation : configLocations) { diff --git a/org.springframework.web/src/test/java/org/springframework/web/context/support/ConfigurationClassWebApplicationContextTests.java b/org.springframework.web/src/test/java/org/springframework/web/context/support/ConfigurationClassWebApplicationContextTests.java index b67cadf6086..92c1799e646 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/context/support/ConfigurationClassWebApplicationContextTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/context/support/ConfigurationClassWebApplicationContextTests.java @@ -16,25 +16,20 @@ package org.springframework.web.context.support; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import static org.junit.matchers.JUnitMatchers.containsString; - -import java.io.IOException; - +import static org.junit.Assert.*; import org.junit.Test; -import org.springframework.context.ApplicationContextException; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; - +/** + * @author Chris Beams + */ public class ConfigurationClassWebApplicationContextTests { @Test public void testSingleWellFormedConfigLocation() { - ConfigurationClassWebApplicationContext ctx = new ConfigurationClassWebApplicationContext(); + AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.setConfigLocation(Config.class.getName()); ctx.refresh(); @@ -42,45 +37,6 @@ public class ConfigurationClassWebApplicationContextTests { assertNotNull(bean); } - @Test - public void testWithoutExplicitlySettingConfigLocations() { - ConfigurationClassWebApplicationContext ctx = new ConfigurationClassWebApplicationContext(); - try { - ctx.refresh(); - fail("expected exception"); - } catch (IllegalArgumentException ex) { - assertThat(ex.getMessage(), containsString( - "Is the 'contextConfigLocations' context-param " + - "and/or init-param set properly in web.xml?")); - } - } - - @Test - public void testMalformedConfigLocation() { - ConfigurationClassWebApplicationContext ctx = new ConfigurationClassWebApplicationContext(); - ctx.setConfigLocation("garbage"); - try { - ctx.refresh(); - fail("expected exception"); - } catch (ApplicationContextException ex) { - assertThat(ex.getCause(), is(IOException.class)); - assertThat(ex.getCause().getMessage(), - containsString("Could not load @Configuration class")); - } - } - - @Test - public void testNonConfigurationClass() { - ConfigurationClassWebApplicationContext ctx = new ConfigurationClassWebApplicationContext(); - ctx.setConfigLocation(NotConfigurationAnnotated.class.getName()); - try { - ctx.refresh(); - fail("expected exception"); - } catch (IllegalArgumentException ex) { - assertThat(ex.getMessage(), - containsString("is not annotated with @Configuration")); - } - } @Configuration static class Config { @@ -92,7 +48,6 @@ public class ConfigurationClassWebApplicationContextTests { static class NotConfigurationAnnotated { } - static class TestBean { + static class TestBean { } - } }