Browse Source

Sync with 3.1.x

* 3.1.x:
  Demonstrate use of @Configuration as meta-annotation
  Prune dead code from JmsTransactionManager#doBegin
  Apply @Configuration BeanNameGenerator consistently
  Improve @Configuration bean name discovery
  Fix infinite recursion bug in nested @Configuration
  Polish static imports
  Minor fix in ServletResponseMethodArgumentResolver
  extracted ResourceUtils.useCachesIfNecessary(URLConnection) method (SP
  prepared for 3.1.1 release
  CustomSQLExceptionTranslatorRegistry/Registrar etc
  revised CustomSQLExceptionTranslatorRegistry/Registrar method naming
  use custom InputStream traversal instead of a full byte array (SPR-911
  PathMatchingResourcePatternResolver preserves caching for JNLP jar con
  Resource "contentLength()" implementations work with OSGi bundle resou
  fixed MethodInvokingJobDetailFactoryBean for compatibility with Quartz
  fixed MethodInvokingJobDetailFactoryBean for compatibility with Quartz
pull/42/head
Chris Beams 14 years ago
parent
commit
3e81482760
  1. 30
      spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotatedGenericBeanDefinition.java
  2. 16
      spring-context-support/src/main/java/org/springframework/scheduling/quartz/MethodInvokingJobDetailFactoryBean.java
  3. 4
      spring-context/src/main/java/org/springframework/context/annotation/AdviceModeImportSelector.java
  4. 4
      spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java
  5. 16
      spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java
  6. 4
      spring-context/src/main/java/org/springframework/context/annotation/AnnotationScopeMetadataResolver.java
  7. 4
      spring-context/src/main/java/org/springframework/context/annotation/AspectJAutoProxyRegistrar.java
  8. 2
      spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java
  9. 10
      spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java
  10. 12
      spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java
  11. 48
      spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java
  12. 62
      spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java
  13. 59
      spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
  14. 4
      spring-context/src/main/java/org/springframework/context/annotation/LoadTimeWeavingConfiguration.java
  15. 13
      spring-context/src/main/java/org/springframework/context/annotation/ScannedGenericBeanDefinition.java
  16. 1
      spring-context/src/test/java/org/springframework/context/annotation/AsmCircularImportDetectionTests.java
  17. 9
      spring-context/src/test/java/org/springframework/context/annotation/ImportAwareTests.java
  18. 94
      spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationBeanNameTests.java
  19. 72
      spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationMetaAnnotationTests.java
  20. 32
      spring-context/src/test/java/org/springframework/context/annotation/configuration/spr8955/Spr8955Parent.java
  21. 36
      spring-context/src/test/java/org/springframework/context/annotation/configuration/spr8955/Spr8955Tests.java
  22. 8
      spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java
  23. 24
      spring-core/src/main/java/org/springframework/core/io/AbstractResource.java
  24. 10
      spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java
  25. 5
      spring-core/src/main/java/org/springframework/core/io/UrlResource.java
  26. 5
      spring-core/src/main/java/org/springframework/core/io/VfsResource.java
  27. 19
      spring-core/src/main/java/org/springframework/core/io/VfsUtils.java
  28. 4
      spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java
  29. 5
      spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderUtils.java
  30. 13
      spring-core/src/main/java/org/springframework/util/ResourceUtils.java
  31. 41
      spring-jdbc/src/main/java/org/springframework/jdbc/support/CustomSQLExceptionTranslatorRegistrar.java
  32. 57
      spring-jdbc/src/main/java/org/springframework/jdbc/support/CustomSQLExceptionTranslatorRegistry.java
  33. 52
      spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java
  34. 12
      spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodesFactory.java
  35. 2
      spring-jdbc/src/test/resources/org/springframework/jdbc/support/test-custom-translators-context.xml
  36. 9
      spring-jms/src/main/java/org/springframework/jms/connection/JmsTransactionManager.java
  37. 3
      spring-web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java
  38. 25
      spring-web/src/test/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContextTests.java
  39. 6
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolver.java
  40. 10
      spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolverTests.java
  41. 7
      src/dist/changelog.txt

30
spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotatedGenericBeanDefinition.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2012 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.
@ -19,6 +19,7 @@ package org.springframework.beans.factory.annotation; @@ -19,6 +19,7 @@ package org.springframework.beans.factory.annotation;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.util.Assert;
/**
* Extension of the {@link org.springframework.beans.factory.support.GenericBeanDefinition}
@ -32,27 +33,46 @@ import org.springframework.core.type.StandardAnnotationMetadata; @@ -32,27 +33,46 @@ import org.springframework.core.type.StandardAnnotationMetadata;
* which also implements the AnnotatedBeanDefinition interface).
*
* @author Juergen Hoeller
* @author Chris Beams
* @since 2.5
* @see AnnotatedBeanDefinition#getMetadata()
* @see org.springframework.core.type.StandardAnnotationMetadata
*/
@SuppressWarnings("serial")
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata annotationMetadata;
private final AnnotationMetadata metadata;
/**
* Create a new AnnotatedGenericBeanDefinition for the given bean class.
* @param beanClass the loaded bean class
*/
public AnnotatedGenericBeanDefinition(Class beanClass) {
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.annotationMetadata = new StandardAnnotationMetadata(beanClass, true);
this.metadata = new StandardAnnotationMetadata(beanClass, true);
}
/**
* Create a new AnnotatedGenericBeanDefinition for the given annotation metadata,
* allowing for ASM-based processing and avoidance of early loading of the bean class.
* Note that this constructor is functionally equivalent to
* {@link org.springframework.context.annotation.ScannedGenericBeanDefinition
* ScannedGenericBeanDefinition}, however the semantics of the latter indicate that
* a bean was discovered specifically via component-scanning as opposed to other
* means.
* @param metadata the annotation metadata for the bean class in question
* @since 3.1.1
*/
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
Assert.notNull(metadata, "AnnotationMetadata must not be null");
setBeanClassName(metadata.getClassName());
this.metadata = metadata;
}
public final AnnotationMetadata getMetadata() {
return this.annotationMetadata;
return this.metadata;
}
}

16
spring-context-support/src/main/java/org/springframework/scheduling/quartz/MethodInvokingJobDetailFactoryBean.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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.
@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
package org.springframework.scheduling.quartz;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -40,6 +41,7 @@ import org.springframework.beans.support.ArgumentConvertingMethodInvoker; @@ -40,6 +41,7 @@ import org.springframework.beans.support.ArgumentConvertingMethodInvoker;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.MethodInvoker;
import org.springframework.util.ReflectionUtils;
/**
* {@link org.springframework.beans.factory.FactoryBean} that exposes a
@ -80,6 +82,8 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod @@ -80,6 +82,8 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
private static Class<?> jobDetailImplClass;
private static Method setResultMethod;
static {
try {
jobDetailImplClass = Class.forName("org.quartz.impl.JobDetailImpl");
@ -87,6 +91,14 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod @@ -87,6 +91,14 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
catch (ClassNotFoundException ex) {
jobDetailImplClass = null;
}
try {
Class jobExecutionContextClass =
QuartzJobBean.class.getClassLoader().loadClass("org.quartz.JobExecutionContext");
setResultMethod = jobExecutionContextClass.getMethod("setResult", Object.class);
}
catch (Exception ex) {
throw new IllegalStateException("Incompatible Quartz API: " + ex);
}
}
@ -296,7 +308,7 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod @@ -296,7 +308,7 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
try {
context.setResult(this.methodInvoker.invoke());
ReflectionUtils.invokeMethod(setResultMethod, context, this.methodInvoker.invoke());
}
catch (InvocationTargetException ex) {
if (ex.getTargetException() instanceof JobExecutionException) {

4
spring-context/src/main/java/org/springframework/context/annotation/AdviceModeImportSelector.java

@ -16,8 +16,6 @@ @@ -16,8 +16,6 @@
package org.springframework.context.annotation;
import static org.springframework.context.annotation.MetadataUtils.attributesFor;
import java.lang.annotation.Annotation;
import org.springframework.core.GenericTypeResolver;
@ -25,6 +23,8 @@ import org.springframework.core.annotation.AnnotationAttributes; @@ -25,6 +23,8 @@ import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
import static org.springframework.context.annotation.MetadataUtils.*;
/**
* Convenient base class for {@link ImportSelector} implementations that select imports
* based on an {@link AdviceMode} value from an annotation (such as the {@code @Enable*}

4
spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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.
@ -109,6 +109,8 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex @@ -109,6 +109,8 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
this.reader.setBeanNameGenerator(beanNameGenerator);
this.scanner.setBeanNameGenerator(beanNameGenerator);
this.getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
/**

16
spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java

@ -16,8 +16,6 @@ @@ -16,8 +16,6 @@
package org.springframework.context.annotation;
import static org.springframework.context.annotation.MetadataUtils.attributesFor;
import java.util.LinkedHashSet;
import java.util.Set;
@ -32,6 +30,8 @@ import org.springframework.beans.factory.support.RootBeanDefinition; @@ -32,6 +30,8 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
import static org.springframework.context.annotation.MetadataUtils.*;
/**
* Utility class that allows for convenient registration of common
* {@link org.springframework.beans.factory.config.BeanPostProcessor} and
@ -56,6 +56,17 @@ public class AnnotationConfigUtils { @@ -56,6 +56,17 @@ public class AnnotationConfigUtils {
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor";
/**
* The bean name of the internally managed BeanNameGenerator for use when processing
* {@link Configuration} classes. Set by {@link AnnotationConfigApplicationContext}
* and {@code AnnotationConfigWebApplicationContext} during bootstrap in order to make
* any custom name generation strategy available to the underlying
* {@link ConfigurationClassPostProcessor}.
* @since 3.1.1
*/
public static final String CONFIGURATION_BEAN_NAME_GENERATOR =
"org.springframework.context.annotation.internalConfigurationBeanNameGenerator";
/**
* The bean name of the internally managed Autowired annotation processor.
*/
@ -249,4 +260,5 @@ public class AnnotationConfigUtils { @@ -249,4 +260,5 @@ public class AnnotationConfigUtils {
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
}

4
spring-context/src/main/java/org/springframework/context/annotation/AnnotationScopeMetadataResolver.java

@ -16,8 +16,6 @@ @@ -16,8 +16,6 @@
package org.springframework.context.annotation;
import static org.springframework.context.annotation.MetadataUtils.attributesFor;
import java.lang.annotation.Annotation;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
@ -25,6 +23,8 @@ import org.springframework.beans.factory.config.BeanDefinition; @@ -25,6 +23,8 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.util.Assert;
import static org.springframework.context.annotation.MetadataUtils.*;
/**
* A {@link ScopeMetadataResolver} implementation that by default checks for
* the presence of Spring's {@link Scope} annotation on the bean class.

4
spring-context/src/main/java/org/springframework/context/annotation/AspectJAutoProxyRegistrar.java

@ -16,13 +16,13 @@ @@ -16,13 +16,13 @@
package org.springframework.context.annotation;
import static org.springframework.context.annotation.MetadataUtils.attributesFor;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import static org.springframework.context.annotation.MetadataUtils.*;
/**
* Registers an {@link org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
* AnnotationAwareAspectJAutoProxyCreator} against the current {@link BeanDefinitionRegistry}

2
spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java

@ -30,9 +30,9 @@ import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; @@ -30,9 +30,9 @@ import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

10
spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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,8 +77,14 @@ public @interface ComponentScan { @@ -77,8 +77,14 @@ public @interface ComponentScan {
/**
* The {@link BeanNameGenerator} class to be used for naming detected components
* within the Spring container.
* <p>The default value of the {@link BeanNameGenerator} interface itself indicates
* that the scanner used to process this {@code @ComponentScan} annotation should
* use its inherited bean name generator, e.g. the default
* {@link AnnotationBeanNameGenerator} or any custom instance supplied to the
* application context at bootstrap time.
* @see AnnotationConfigApplicationContext#setBeanNameGenerator(BeanNameGenerator)
*/
Class<? extends BeanNameGenerator> nameGenerator() default AnnotationBeanNameGenerator.class;
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
/**
* The {@link ScopeMetadataResolver} to be used for resolving the scope of detected components.

12
spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java

@ -51,11 +51,16 @@ class ComponentScanAnnotationParser { @@ -51,11 +51,16 @@ class ComponentScanAnnotationParser {
private final BeanDefinitionRegistry registry;
private final BeanNameGenerator beanNameGenerator;
public ComponentScanAnnotationParser(
ResourceLoader resourceLoader, Environment environment, BeanDefinitionRegistry registry) {
ResourceLoader resourceLoader, Environment environment,
BeanNameGenerator beanNameGenerator, BeanDefinitionRegistry registry) {
this.resourceLoader = resourceLoader;
this.environment = environment;
this.beanNameGenerator = beanNameGenerator;
this.registry = registry;
}
@ -71,7 +76,10 @@ class ComponentScanAnnotationParser { @@ -71,7 +76,10 @@ class ComponentScanAnnotationParser {
scanner.setResourceLoader(this.resourceLoader);
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
boolean useInheritedGenerator = BeanNameGenerator.class.equals(generatorClass);
scanner.setBeanNameGenerator(useInheritedGenerator
? this.beanNameGenerator
: BeanUtils.instantiateClass(generatorClass));
ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
if (scopedProxyMode != ScopedProxyMode.DEFAULT) {

48
spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java

@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
package org.springframework.context.annotation;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
@ -29,6 +28,7 @@ import org.apache.commons.logging.Log; @@ -29,6 +28,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.config.BeanDefinition;
@ -37,12 +37,10 @@ import org.springframework.beans.factory.parsing.Location; @@ -37,12 +37,10 @@ import org.springframework.beans.factory.parsing.Location;
import org.springframework.beans.factory.parsing.Problem;
import org.springframework.beans.factory.parsing.ProblemReporter;
import org.springframework.beans.factory.parsing.SourceExtractor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
@ -50,8 +48,8 @@ import org.springframework.core.io.Resource; @@ -50,8 +48,8 @@ import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import static org.springframework.context.annotation.MetadataUtils.*;
@ -85,6 +83,8 @@ class ConfigurationClassBeanDefinitionReader { @@ -85,6 +83,8 @@ class ConfigurationClassBeanDefinitionReader {
private final Environment environment;
private final BeanNameGenerator beanNameGenerator;
/**
* Create a new {@link ConfigurationClassBeanDefinitionReader} instance that will be used
@ -92,16 +92,20 @@ class ConfigurationClassBeanDefinitionReader { @@ -92,16 +92,20 @@ class ConfigurationClassBeanDefinitionReader {
* @param problemReporter
* @param metadataReaderFactory
*/
public ConfigurationClassBeanDefinitionReader(BeanDefinitionRegistry registry, SourceExtractor sourceExtractor,
public ConfigurationClassBeanDefinitionReader(
BeanDefinitionRegistry registry, SourceExtractor sourceExtractor,
ProblemReporter problemReporter, MetadataReaderFactory metadataReaderFactory,
ResourceLoader resourceLoader, Environment environment) {
ResourceLoader resourceLoader, Environment environment,
BeanNameGenerator beanNameGenerator) {
Assert.notNull(beanNameGenerator, "BeanNameGenerator must not be null");
this.registry = registry;
this.sourceExtractor = sourceExtractor;
this.problemReporter = problemReporter;
this.metadataReaderFactory = metadataReaderFactory;
this.resourceLoader = resourceLoader;
this.environment = environment;
this.beanNameGenerator = beanNameGenerator;
}
@ -135,39 +139,21 @@ class ConfigurationClassBeanDefinitionReader { @@ -135,39 +139,21 @@ class ConfigurationClassBeanDefinitionReader {
return;
}
BeanDefinition configBeanDef = new GenericBeanDefinition();
String className = configClass.getMetadata().getClassName();
AnnotationMetadata metadata = configClass.getMetadata();
BeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
String className = metadata.getClassName();
configBeanDef.setBeanClassName(className);
MetadataReader reader;
try {
reader = this.metadataReaderFactory.getMetadataReader(className);
}
catch (IOException ex) {
throw new IllegalStateException("Could not create MetadataReader for class " + className);
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) {
Map<String, Object> configAttributes =
reader.getAnnotationMetadata().getAnnotationAttributes(Configuration.class.getName());
// has the 'value' attribute of @Configuration been set?
String configBeanName = (String) configAttributes.get("value");
if (StringUtils.hasText(configBeanName)) {
// yes -> register the configuration class bean with this name
this.registry.registerBeanDefinition(configBeanName, configBeanDef);
}
else {
// no -> register the configuration class bean with a generated name
configBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName((AbstractBeanDefinition)configBeanDef, this.registry);
}
String configBeanName = this.beanNameGenerator.generateBeanName(configBeanDef, this.registry);
this.registry.registerBeanDefinition(configBeanName, configBeanDef);
configClass.setBeanName(configBeanName);
if (logger.isDebugEnabled()) {
logger.debug(String.format("Registered bean definition for imported @Configuration class %s", configBeanName));
}
}
else {
AnnotationMetadata metadata = reader.getAnnotationMetadata();
this.problemReporter.error(
new InvalidConfigurationImportProblem(className, reader.getResource(), metadata));
new InvalidConfigurationImportProblem(className, configClass.getResource(), metadata));
}
}

62
spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java

@ -16,8 +16,6 @@ @@ -16,8 +16,6 @@
package org.springframework.context.annotation;
import static org.springframework.context.annotation.MetadataUtils.attributesFor;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
@ -38,6 +36,7 @@ import org.springframework.beans.factory.parsing.Problem; @@ -38,6 +36,7 @@ import org.springframework.beans.factory.parsing.Problem;
import org.springframework.beans.factory.parsing.ProblemReporter;
import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
@ -51,6 +50,8 @@ import org.springframework.core.type.classreading.MetadataReaderFactory; @@ -51,6 +50,8 @@ import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.util.StringUtils;
import static org.springframework.context.annotation.MetadataUtils.*;
/**
* Parses a {@link Configuration} class definition, populating a collection of
* {@link ConfigurationClass} objects (parsing a single Configuration class may result in
@ -77,6 +78,8 @@ class ConfigurationClassParser { @@ -77,6 +78,8 @@ class ConfigurationClassParser {
private final ImportStack importStack = new ImportStack();
private final Set<String> knownSuperclasses = new LinkedHashSet<String>();
private final Set<ConfigurationClass> configurationClasses =
new LinkedHashSet<ConfigurationClass>();
@ -98,14 +101,16 @@ class ConfigurationClassParser { @@ -98,14 +101,16 @@ class ConfigurationClassParser {
*/
public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
ProblemReporter problemReporter, Environment environment,
ResourceLoader resourceLoader, BeanDefinitionRegistry registry) {
ResourceLoader resourceLoader, BeanNameGenerator beanNameGenerator,
BeanDefinitionRegistry registry) {
this.metadataReaderFactory = metadataReaderFactory;
this.problemReporter = problemReporter;
this.environment = environment;
this.resourceLoader = resourceLoader;
this.registry = registry;
this.componentScanParser =
new ComponentScanAnnotationParser(this.resourceLoader, this.environment, this.registry);
this.componentScanParser = new ComponentScanAnnotationParser(
resourceLoader, environment, beanNameGenerator, registry);
}
@ -138,23 +143,12 @@ class ConfigurationClassParser { @@ -138,23 +143,12 @@ class ConfigurationClassParser {
}
}
while (metadata != null) {
doProcessConfigurationClass(configClass, metadata);
String superClassName = metadata.getSuperClassName();
if (superClassName != null && !Object.class.getName().equals(superClassName)) {
if (metadata instanceof StandardAnnotationMetadata) {
Class<?> clazz = ((StandardAnnotationMetadata) metadata).getIntrospectedClass();
metadata = new StandardAnnotationMetadata(clazz.getSuperclass(), true);
}
else {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(superClassName);
metadata = reader.getAnnotationMetadata();
}
}
else {
metadata = null;
}
// recursively process the configuration class and its superclass hierarchy
do {
metadata = doProcessConfigurationClass(configClass, metadata);
}
while (metadata != null);
if (this.configurationClasses.contains(configClass) && configClass.getBeanName() != null) {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
@ -164,7 +158,11 @@ class ConfigurationClassParser { @@ -164,7 +158,11 @@ class ConfigurationClassParser {
this.configurationClasses.add(configClass);
}
protected void doProcessConfigurationClass(ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
/**
* @return annotation metadata of superclass, null if none found or previously processed
*/
protected AnnotationMetadata doProcessConfigurationClass(
ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
// recursively process any member (nested) classes first
for (String memberClassName : metadata.getMemberClassNames()) {
@ -227,8 +225,26 @@ class ConfigurationClassParser { @@ -227,8 +225,26 @@ class ConfigurationClassParser {
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
}
// process superclass, if any
if (metadata.hasSuperClass()) {
String superclass = metadata.getSuperClassName();
if (this.knownSuperclasses.add(superclass)) {
// superclass found, return its annotation metadata and recurse
if (metadata instanceof StandardAnnotationMetadata) {
Class<?> clazz = ((StandardAnnotationMetadata) metadata).getIntrospectedClass();
return new StandardAnnotationMetadata(clazz.getSuperclass(), true);
}
else {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(superclass);
return reader.getAnnotationMetadata();
}
}
}
// no superclass, processing is complete
return null;
}
/**
* Return a list of attribute maps for all declarations of the given annotation

59
spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java

@ -46,6 +46,7 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition; @@ -46,6 +46,7 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
@ -65,6 +66,8 @@ import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; @@ -65,6 +66,8 @@ import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import static org.springframework.context.annotation.AnnotationConfigUtils.*;
/**
* {@link BeanFactoryPostProcessor} used for bootstrapping processing of
* {@link Configuration @Configuration} classes.
@ -112,6 +115,8 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo @@ -112,6 +115,8 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
private ConfigurationClassBeanDefinitionReader reader;
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
/**
* Set the {@link SourceExtractor} to use for generated bean definitions
@ -142,6 +147,26 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo @@ -142,6 +147,26 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
this.setMetadataReaderFactoryCalled = true;
}
/**
* Set the {@link BeanNameGenerator} to be used when registering imported and nested
* {@link Configuration} classes. The default is {@link AnnotationBeanNameGenerator}.
* <p>Note that this strategy does <em>not</em> apply to {@link Bean} methods.
* <p>This setter is typically only appropriate when configuring the post-processor as
* a standalone bean definition in XML, e.g. not using the dedicated
* {@code AnnotationConfig*} application contexts or the {@code
* <context:annotation-config>} element. Any bean name generator specified against
* the application context will take precedence over any value set here.
* @param beanNameGenerator the strategy to use when generating configuration class
* bean names
* @since 3.1.1
* @see AnnotationConfigApplicationContext#setBeanNameGenerator(BeanNameGenerator)
* @see AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR
*/
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
Assert.notNull(beanNameGenerator, "BeanNameGenerator must not be null");
this.beanNameGenerator = beanNameGenerator;
}
public void setEnvironment(Environment environment) {
Assert.notNull(environment, "Environment must not be null");
this.environment = environment;
@ -197,14 +222,6 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo @@ -197,14 +222,6 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
enhanceConfigurationClasses(beanFactory);
}
private ConfigurationClassBeanDefinitionReader getConfigurationClassBeanDefinitionReader(BeanDefinitionRegistry registry) {
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor,
this.problemReporter, this.metadataReaderFactory, this.resourceLoader, this.environment);
}
return this.reader;
}
/**
* Build and validate a configuration model based on the registry of
* {@link Configuration} classes.
@ -223,9 +240,19 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo @@ -223,9 +240,19 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
return;
}
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry singletonRegistry = null;
if (registry instanceof SingletonBeanRegistry) {
singletonRegistry = (SingletonBeanRegistry) registry;
if (singletonRegistry.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) {
this.beanNameGenerator = (BeanNameGenerator) singletonRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
}
}
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, registry);
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.beanNameGenerator, registry);
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
@ -258,12 +285,18 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo @@ -258,12 +285,18 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
}
// Read the model and create bean definitions based on its content
this.getConfigurationClassBeanDefinitionReader(registry).loadBeanDefinitions(parser.getConfigurationClasses());
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.problemReporter,
this.metadataReaderFactory, this.resourceLoader, this.environment,
this.beanNameGenerator);
}
this.reader.loadBeanDefinitions(parser.getConfigurationClasses());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (registry instanceof SingletonBeanRegistry) {
if (!((SingletonBeanRegistry) registry).containsSingleton("importRegistry")) {
((SingletonBeanRegistry) registry).registerSingleton("importRegistry", parser.getImportRegistry());
if (singletonRegistry != null) {
if (!singletonRegistry.containsSingleton("importRegistry")) {
singletonRegistry.registerSingleton("importRegistry", parser.getImportRegistry());
}
}
}

4
spring-context/src/main/java/org/springframework/context/annotation/LoadTimeWeavingConfiguration.java

@ -16,8 +16,6 @@ @@ -16,8 +16,6 @@
package org.springframework.context.annotation;
import static org.springframework.context.weaving.AspectJWeavingEnabler.ASPECTJ_AOP_XML_RESOURCE;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
@ -30,6 +28,8 @@ import org.springframework.core.type.AnnotationMetadata; @@ -30,6 +28,8 @@ import org.springframework.core.type.AnnotationMetadata;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.util.Assert;
import static org.springframework.context.weaving.AspectJWeavingEnabler.*;
/**
* {@code @Configuration} class that registers a {@link LoadTimeWeaver} bean.
*

13
spring-context/src/main/java/org/springframework/context/annotation/ScannedGenericBeanDefinition.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2012 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.
@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
package org.springframework.context.annotation;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
@ -27,16 +28,22 @@ import org.springframework.util.Assert; @@ -27,16 +28,22 @@ import org.springframework.util.Assert;
* class, based on an ASM ClassReader, with support for annotation metadata exposed
* through the {@link AnnotatedBeanDefinition} interface.
*
* <p>This class does <i>not</i> load the bean <code>Class</code> early.
* <p>This class does <i>not</i> load the bean {@code Class} early.
* It rather retrieves all relevant metadata from the ".class" file itself,
* parsed with the ASM ClassReader.
* parsed with the ASM ClassReader. It is functionally equivalent to
* {@link AnnotatedGenericBeanDefinition#AnnotatedGenericBeanDefinition(AnnotationMetadata)}
* but distinguishes by type beans that have been <em>scanned</em> vs those that have
* been otherwise registered or detected by other means.
*
* @author Juergen Hoeller
* @author Chris Beams
* @since 2.5
* @see #getMetadata()
* @see #getBeanClassName()
* @see org.springframework.core.type.classreading.MetadataReaderFactory
* @see AnnotatedGenericBeanDefinition
*/
@SuppressWarnings("serial")
public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;

1
spring-context/src/test/java/org/springframework/context/annotation/AsmCircularImportDetectionTests.java

@ -40,6 +40,7 @@ public class AsmCircularImportDetectionTests extends AbstractCircularImportDetec @@ -40,6 +40,7 @@ public class AsmCircularImportDetectionTests extends AbstractCircularImportDetec
new FailFastProblemReporter(),
new StandardEnvironment(),
new DefaultResourceLoader(),
new AnnotationBeanNameGenerator(),
new DefaultListableBeanFactory());
}

9
spring-context/src/test/java/org/springframework/context/annotation/ImportAwareTests.java

@ -16,11 +16,6 @@ @@ -16,11 +16,6 @@
package org.springframework.context.annotation;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.springframework.context.annotation.MetadataUtils.attributesFor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@ -35,6 +30,10 @@ import org.springframework.core.annotation.AnnotationAttributes; @@ -35,6 +30,10 @@ import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.context.annotation.MetadataUtils.*;
/**
* Tests that an ImportAware @Configuration classes gets injected with the
* annotation metadata of the @Configuration class that imported it.

94
spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationBeanNameTests.java

@ -0,0 +1,94 @@ @@ -0,0 +1,94 @@
/*
* Copyright 2002-2012 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.configuration;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
/**
* Unit tests ensuring that configuration class bean names as expressed via @Configuration
* or @Component 'value' attributes are indeed respected, and that customization of bean
* naming through a BeanNameGenerator strategy works as expected.
*
* @author Chris Beams
* @since 3.1.1
*/
public class ConfigurationBeanNameTests {
@Test
public void registerOuterConfig() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(A.class);
ctx.refresh();
assertThat(ctx.containsBean("outer"), is(true));
assertThat(ctx.containsBean("imported"), is(true));
assertThat(ctx.containsBean("nested"), is(true));
assertThat(ctx.containsBean("nestedBean"), is(true));
}
@Test
public void registerNestedConfig() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(A.B.class);
ctx.refresh();
assertThat(ctx.containsBean("outer"), is(false));
assertThat(ctx.containsBean("imported"), is(false));
assertThat(ctx.containsBean("nested"), is(true));
assertThat(ctx.containsBean("nestedBean"), is(true));
}
@Test
public void registerOuterConfig_withBeanNameGenerator() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.setBeanNameGenerator(new AnnotationBeanNameGenerator() {
public String generateBeanName(
BeanDefinition definition, BeanDefinitionRegistry registry) {
return "custom-" + super.generateBeanName(definition, registry);
}
});
ctx.register(A.class);
ctx.refresh();
assertThat(ctx.containsBean("custom-outer"), is(true));
assertThat(ctx.containsBean("custom-imported"), is(true));
assertThat(ctx.containsBean("custom-nested"), is(true));
assertThat(ctx.containsBean("nestedBean"), is(true));
}
@Configuration("outer")
@Import(C.class)
static class A {
@Component("nested")
static class B {
@Bean public String nestedBean() { return ""; }
}
}
@Configuration("imported")
static class C {
@Bean public String s() { return "s"; }
}
}

72
spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationMetaAnnotationTests.java

@ -0,0 +1,72 @@ @@ -0,0 +1,72 @@
/*
* Copyright 2002-2012 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.configuration;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import test.beans.TestBean;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
/**
* Ensures that @Configuration is supported properly as a meta-annotation.
*
* @author Chris Beams
*/
public class ConfigurationMetaAnnotationTests {
@Test
public void customConfigurationStereotype() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(Config.class);
ctx.refresh();
assertThat(ctx.containsBean("customName"), is(true));
TestBean a = ctx.getBean("a", TestBean.class);
TestBean b = ctx.getBean("b", TestBean.class);
assertThat(b, sameInstance(a.getSpouse()));
}
@TestConfiguration("customName")
static class Config {
@Bean
public TestBean a() {
TestBean a = new TestBean();
a.setSpouse(b());
return a;
}
@Bean
public TestBean b() {
return new TestBean();
}
}
@Configuration
@Retention(RetentionPolicy.RUNTIME)
public @interface TestConfiguration {
String value() default "";
}
}

32
spring-context/src/test/java/org/springframework/context/annotation/configuration/spr8955/Spr8955Parent.java

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
/*
* Copyright 2002-2012 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.configuration.spr8955;
import org.springframework.stereotype.Component;
/**
* @author Chris Beams
* @author Willem Dekker
*/
abstract class Spr8955Parent {
@Component
static class Spr8955Child extends Spr8955Parent {
}
}

36
spring-context/src/test/java/org/springframework/context/annotation/configuration/spr8955/Spr8955Tests.java

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
/*
* Copyright 2002-2012 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.configuration.spr8955;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author Chris Beams
* @author Willem Dekker
*/
public class Spr8955Tests {
@Test
public void repro() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("org.springframework.context.annotation.configuration.spr8955");
ctx.refresh();
}
}

8
spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java

@ -95,7 +95,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { @@ -95,7 +95,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
else {
// Try a URL connection content-length header...
URLConnection con = url.openConnection();
con.setUseCaches(false);
ResourceUtils.useCachesIfNecessary(con);
HttpURLConnection httpCon =
(con instanceof HttpURLConnection ? (HttpURLConnection) con : null);
if (httpCon != null) {
@ -152,12 +152,12 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { @@ -152,12 +152,12 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
URL url = getURL();
if (ResourceUtils.isFileURL(url)) {
// Proceed with file system resolution...
return super.contentLength();
return getFile().length();
}
else {
// Try a URL connection content-length header...
URLConnection con = url.openConnection();
con.setUseCaches(false);
ResourceUtils.useCachesIfNecessary(con);
if (con instanceof HttpURLConnection) {
((HttpURLConnection) con).setRequestMethod("HEAD");
}
@ -175,7 +175,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { @@ -175,7 +175,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
else {
// Try a URL connection last-modified header...
URLConnection con = url.openConnection();
con.setUseCaches(false);
ResourceUtils.useCachesIfNecessary(con);
if (con instanceof HttpURLConnection) {
((HttpURLConnection) con).setRequestMethod("HEAD");
}

24
spring-core/src/main/java/org/springframework/core/io/AbstractResource.java

@ -108,12 +108,28 @@ public abstract class AbstractResource implements Resource { @@ -108,12 +108,28 @@ public abstract class AbstractResource implements Resource {
}
/**
* This implementation checks the length of the underlying File,
* if available.
* @see #getFile()
* This implementation reads the entire InputStream to calculate the
* content length. Subclasses will almost always be able to provide
* a more optimal version of this, e.g. checking a File length.
* @see #getInputStream()
*/
public long contentLength() throws IOException {
return getFile().length();
InputStream is = getInputStream();
try {
long size = 0;
byte[] buf = new byte[255];
for (int read = is.read(buf); read != -1;) {
size += read;
}
return size;
}
finally {
try {
is.close();
}
catch (IOException ex) {
}
}
}
/**

10
spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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.
@ -139,6 +139,14 @@ public class FileSystemResource extends AbstractResource implements WritableReso @@ -139,6 +139,14 @@ public class FileSystemResource extends AbstractResource implements WritableReso
return this.file;
}
/**
* This implementation returns the underlying File's length.
*/
@Override
public long contentLength() throws IOException {
return this.file.length();
}
/**
* This implementation creates a FileSystemResource, applying the given path
* relative to the path of the underlying file of this resource descriptor.

5
spring-core/src/main/java/org/springframework/core/io/UrlResource.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2012 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.
@ -26,6 +26,7 @@ import java.net.URL; @@ -26,6 +26,7 @@ import java.net.URL;
import java.net.URLConnection;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
/**
@ -119,7 +120,7 @@ public class UrlResource extends AbstractFileResolvingResource { @@ -119,7 +120,7 @@ public class UrlResource extends AbstractFileResolvingResource {
*/
public InputStream getInputStream() throws IOException {
URLConnection con = this.url.openConnection();
con.setUseCaches(false);
ResourceUtils.useCachesIfNecessary(con);
try {
return con.getInputStream();
}

5
spring-core/src/main/java/org/springframework/core/io/VfsResource.java

@ -86,6 +86,11 @@ public class VfsResource extends AbstractResource { @@ -86,6 +86,11 @@ public class VfsResource extends AbstractResource {
return VfsUtils.getFile(this.resource);
}
@Override
public long contentLength() throws IOException {
return VfsUtils.getSize(this.resource);
}
@Override
public long lastModified() throws IOException {
return VfsUtils.getLastModified(this.resource);

19
spring-core/src/main/java/org/springframework/core/io/VfsUtils.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2012 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.
@ -27,6 +27,7 @@ import java.net.URL; @@ -27,6 +27,7 @@ import java.net.URL;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.NestedIOException;
import org.springframework.util.ReflectionUtils;
@ -58,14 +59,15 @@ public abstract class VfsUtils { @@ -58,14 +59,15 @@ public abstract class VfsUtils {
private static Method VFS_METHOD_GET_ROOT_URI = null;
private static Method VIRTUAL_FILE_METHOD_EXISTS = null;
private static Method VIRTUAL_FILE_METHOD_GET_INPUT_STREAM;
private static Method VIRTUAL_FILE_METHOD_GET_SIZE;
private static Method VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED;
private static Method VIRTUAL_FILE_METHOD_GET_CHILD;
private static Method VIRTUAL_FILE_METHOD_GET_INPUT_STREAM;
private static Method VIRTUAL_FILE_METHOD_TO_URL;
private static Method VIRTUAL_FILE_METHOD_TO_URI;
private static Method VIRTUAL_FILE_METHOD_GET_NAME;
private static Method VIRTUAL_FILE_METHOD_GET_PATH_NAME;
private static Method VIRTUAL_FILE_METHOD_GET_CHILD;
protected static Class<?> VIRTUAL_FILE_VISITOR_INTERFACE;
protected static Method VIRTUAL_FILE_METHOD_VISIT;
@ -101,9 +103,10 @@ public abstract class VfsUtils { @@ -101,9 +103,10 @@ public abstract class VfsUtils {
if (logger.isDebugEnabled())
logger.debug("JBoss VFS packages for JBoss AS 5 found");
} catch (ClassNotFoundException ex1) {
}
catch (ClassNotFoundException ex2) {
logger.error("JBoss VFS packages (for both JBoss AS 5 and 6) were not found - JBoss VFS support disabled");
throw new IllegalStateException("Cannot detect JBoss VFS packages", ex1);
throw new IllegalStateException("Cannot detect JBoss VFS packages", ex2);
}
}
@ -117,8 +120,8 @@ public abstract class VfsUtils { @@ -117,8 +120,8 @@ public abstract class VfsUtils {
Class<?> virtualFile = loader.loadClass(pkg + "VirtualFile");
VIRTUAL_FILE_METHOD_EXISTS = ReflectionUtils.findMethod(virtualFile, "exists");
VIRTUAL_FILE_METHOD_GET_SIZE = ReflectionUtils.findMethod(virtualFile, "getSize");
VIRTUAL_FILE_METHOD_GET_INPUT_STREAM = ReflectionUtils.findMethod(virtualFile, "openStream");
VIRTUAL_FILE_METHOD_GET_SIZE = ReflectionUtils.findMethod(virtualFile, "getSize");
VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED = ReflectionUtils.findMethod(virtualFile, "getLastModified");
VIRTUAL_FILE_METHOD_TO_URI = ReflectionUtils.findMethod(virtualFile, "toURI");
VIRTUAL_FILE_METHOD_TO_URL = ReflectionUtils.findMethod(virtualFile, "toURL");
@ -183,6 +186,10 @@ public abstract class VfsUtils { @@ -183,6 +186,10 @@ public abstract class VfsUtils {
}
}
static long getSize(Object vfsResource) throws IOException {
return (Long) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_SIZE, vfsResource);
}
static long getLastModified(Object vfsResource) throws IOException {
return (Long) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED, vfsResource);
}

4
spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2012 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.
@ -433,7 +433,7 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol @@ -433,7 +433,7 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
if (con instanceof JarURLConnection) {
// Should usually be the case for traditional JAR files.
JarURLConnection jarCon = (JarURLConnection) con;
jarCon.setUseCaches(false);
ResourceUtils.useCachesIfNecessary(jarCon);
jarFile = jarCon.getJarFile();
jarFileUrl = jarCon.getJarFileURL().toExternalForm();
JarEntry jarEntry = jarCon.getJarEntry();

5
spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderUtils.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2006 the original author or authors.
* Copyright 2002-2012 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.
@ -26,6 +26,7 @@ import java.util.Properties; @@ -26,6 +26,7 @@ import java.util.Properties;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ResourceUtils;
/**
* Convenient utility methods for loading of <code>java.util.Properties</code>,
@ -106,7 +107,7 @@ public abstract class PropertiesLoaderUtils { @@ -106,7 +107,7 @@ public abstract class PropertiesLoaderUtils {
InputStream is = null;
try {
URLConnection con = url.openConnection();
con.setUseCaches(false);
ResourceUtils.useCachesIfNecessary(con);
is = con.getInputStream();
properties.load(is);
}

13
spring-core/src/main/java/org/springframework/util/ResourceUtils.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2012 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.
@ -22,6 +22,7 @@ import java.net.MalformedURLException; @@ -22,6 +22,7 @@ import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
/**
* Utility methods for resolving resource locations to files in the
@ -328,4 +329,14 @@ public abstract class ResourceUtils { @@ -328,4 +329,14 @@ public abstract class ResourceUtils {
return new URI(StringUtils.replace(location, " ", "%20"));
}
/**
* Set the {@link URLConnection#setUseCaches "useCaches"} flag on the
* given connection, preferring <code>false</code> but leaving the
* flag at <code>true</code> for JNLP based resources.
* @param con the URLConnection to set the flag on
*/
public static void useCachesIfNecessary(URLConnection con) {
con.setUseCaches(con.getClass().getName().startsWith("JNLP"));
}
}

41
spring-jdbc/src/main/java/org/springframework/jdbc/support/CustomSQLExceptionTranslatorRegistrar.java

@ -16,53 +16,42 @@ @@ -16,53 +16,42 @@
package org.springframework.jdbc.support;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
/**
* Registry for registering custom {@link org.springframework.jdbc.support.SQLExceptionTranslator}.
* Registry for registering custom {@link org.springframework.jdbc.support.SQLExceptionTranslator}
* instances for specific databases.
*
* @author Thomas Risberg
* @since 3.1
* @since 3.1.1
*/
public class CustomSQLExceptionTranslatorRegistrar implements InitializingBean {
private static final Log logger = LogFactory.getLog(CustomSQLExceptionTranslatorRegistrar.class);
/**
* Map registry to hold custom translators specific databases.
* Key is the database product name as defined in the
* {@link org.springframework.jdbc.support.SQLErrorCodesFactory}.
*/
private final Map<String, SQLExceptionTranslator> sqlExceptionTranslators =
new HashMap<String, SQLExceptionTranslator>();
private final Map<String, SQLExceptionTranslator> translators = new HashMap<String, SQLExceptionTranslator>();
/**
* Setter for a Map of translators where the key must be the database name as defined in the
* sql-error-codes.xml file. This method is used when this registry is used in an application context.
* <p>Note that any existing translators will remain unless there is a match in the database name at which
* point the new translator will replace the existing one.
*
* @param sqlExceptionTranslators
* Setter for a Map of {@link SQLExceptionTranslator} references where the key must
* be the database name as defined in the <code>sql-error-codes.xml</code> file.
* <p>Note that any existing translators will remain unless there is a match in the
* database name, at which point the new translator will replace the existing one.
*/
public void setSqlExceptionTranslators(Map<String, SQLExceptionTranslator> sqlExceptionTranslators) {
this.sqlExceptionTranslators.putAll(sqlExceptionTranslators);
public void setTranslators(Map<String, SQLExceptionTranslator> translators) {
this.translators.putAll(translators);
}
public void afterPropertiesSet() throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("Registering custom SQL exception translators for database(s): " +
sqlExceptionTranslators.keySet());
}
for (String dbName : sqlExceptionTranslators.keySet()) {
CustomSQLExceptionTranslatorRegistry.getInstance()
.registerSqlExceptionTranslator(dbName, sqlExceptionTranslators.get(dbName));
public void afterPropertiesSet() {
for (String dbName : this.translators.keySet()) {
CustomSQLExceptionTranslatorRegistry.getInstance().registerTranslator(dbName, this.translators.get(dbName));
}
}
}

57
spring-jdbc/src/main/java/org/springframework/jdbc/support/CustomSQLExceptionTranslatorRegistry.java

@ -16,45 +16,25 @@ @@ -16,45 +16,25 @@
package org.springframework.jdbc.support;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.PatternMatchUtils;
/**
* Registry for custom {@link org.springframework.jdbc.support.SQLExceptionTranslator} instances associated with
* specific databases allowing for overriding translation based on values contained in the configuration file
* named "sql-error-codes.xml".
*
* @author Thomas Risberg
* @since 3.1
* @since 3.1.1
* @see SQLErrorCodesFactory
*/
public class CustomSQLExceptionTranslatorRegistry {
private static final Log logger = LogFactory.getLog(CustomSQLExceptionTranslatorRegistry.class);
/**
* Map registry to hold custom translators specific databases.
* Key is the database product name as defined in the
* {@link org.springframework.jdbc.support.SQLErrorCodesFactory}.
*/
private final Map<String, SQLExceptionTranslator> sqlExceptionTranslatorRegistry =
new HashMap<String, SQLExceptionTranslator>();
/**
* Keep track of a single instance so we can return it to classes that request it.
*/
@ -70,7 +50,15 @@ public class CustomSQLExceptionTranslatorRegistry { @@ -70,7 +50,15 @@ public class CustomSQLExceptionTranslatorRegistry {
/**
* Create a new instance of the {@link org.springframework.jdbc.support.CustomSQLExceptionTranslatorRegistry} class.
* Map registry to hold custom translators specific databases.
* Key is the database product name as defined in the
* {@link org.springframework.jdbc.support.SQLErrorCodesFactory}.
*/
private final Map<String, SQLExceptionTranslator> translatorMap = new HashMap<String, SQLExceptionTranslator>();
/**
* Create a new instance of the {@link CustomSQLExceptionTranslatorRegistry} class.
* <p>Not public to enforce Singleton design pattern.
*/
private CustomSQLExceptionTranslatorRegistry() {
@ -78,25 +66,28 @@ public class CustomSQLExceptionTranslatorRegistry { @@ -78,25 +66,28 @@ public class CustomSQLExceptionTranslatorRegistry {
/**
* Register a new custom translator for the specified database name.
*
* @param dbName the database name
* @param sqlExceptionTranslator the custom translator
* @param translator the custom translator
*/
public void registerSqlExceptionTranslator(String dbName, SQLExceptionTranslator sqlExceptionTranslator) {
SQLExceptionTranslator replaced = sqlExceptionTranslatorRegistry.put(dbName, sqlExceptionTranslator);
public void registerTranslator(String dbName, SQLExceptionTranslator translator) {
SQLExceptionTranslator replaced = translatorMap.put(dbName, translator);
if (replaced != null) {
logger.warn("Replacing custom translator '" + replaced +
"' for database " + dbName +
" with '" + sqlExceptionTranslator + "'");
logger.warn("Replacing custom translator [" + replaced + "] for database '" + dbName +
"' with [" + translator + "]");
}
else {
logger.info("Adding custom translator '" + sqlExceptionTranslator.getClass().getSimpleName() +
"' for database " + dbName);
logger.info("Adding custom translator of type [" + translator.getClass().getName() +
"] for database '" + dbName + "'");
}
}
public SQLExceptionTranslator findSqlExceptionTranslatorForDatabase(String dbName) {
return sqlExceptionTranslatorRegistry.get(dbName);
/**
* Find a custom translator for the specified database.
* @param dbName the database name
* @return the custom translator, or <code>null</code> if none found
*/
public SQLExceptionTranslator findTranslatorForDatabase(String dbName) {
return this.translatorMap.get(dbName);
}
}

52
spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java

@ -17,7 +17,6 @@ @@ -17,7 +17,6 @@
package org.springframework.jdbc.support;
import org.springframework.util.StringUtils;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
/**
* JavaBean for holding JDBC error codes for a particular database.
@ -38,8 +37,6 @@ public class SQLErrorCodes { @@ -38,8 +37,6 @@ public class SQLErrorCodes {
private boolean useSqlStateForTranslation = false;
private SQLExceptionTranslator customSqlExceptionTranslator = null;
private String[] badSqlGrammarCodes = new String[0];
private String[] invalidResultSetAccessCodes = new String[0];
@ -62,6 +59,8 @@ public class SQLErrorCodes { @@ -62,6 +59,8 @@ public class SQLErrorCodes {
private CustomSQLErrorCodesTranslation[] customTranslations;
private SQLExceptionTranslator customSqlExceptionTranslator;
/**
* Set this property if the database name contains spaces,
@ -100,31 +99,6 @@ public class SQLErrorCodes { @@ -100,31 +99,6 @@ public class SQLErrorCodes {
return this.useSqlStateForTranslation;
}
public SQLExceptionTranslator getCustomSqlExceptionTranslator() {
return customSqlExceptionTranslator;
}
public void setCustomSqlExceptionTranslator(SQLExceptionTranslator customSqlExceptionTranslator) {
this.customSqlExceptionTranslator = customSqlExceptionTranslator;
}
public void setCustomSqlExceptionTranslatorClass(Class customSqlExceptionTranslatorClass) {
if (customSqlExceptionTranslatorClass != null) {
try {
this.customSqlExceptionTranslator =
(SQLExceptionTranslator) customSqlExceptionTranslatorClass.newInstance();
}
catch (InstantiationException e) {
throw new InvalidDataAccessResourceUsageException(
"Unable to instantiate " + customSqlExceptionTranslatorClass.getName(), e);
}
catch (IllegalAccessException e) {
throw new InvalidDataAccessResourceUsageException(
"Unable to instantiate " + customSqlExceptionTranslatorClass.getName(), e);
}
}
}
public void setBadSqlGrammarCodes(String[] badSqlGrammarCodes) {
this.badSqlGrammarCodes = StringUtils.sortStringArray(badSqlGrammarCodes);
}
@ -213,4 +187,26 @@ public class SQLErrorCodes { @@ -213,4 +187,26 @@ public class SQLErrorCodes {
return this.customTranslations;
}
public void setCustomSqlExceptionTranslatorClass(Class<? extends SQLExceptionTranslator> customTranslatorClass) {
if (customTranslatorClass != null) {
try {
this.customSqlExceptionTranslator = customTranslatorClass.newInstance();
}
catch (Exception ex) {
throw new IllegalStateException("Unable to instantiate custom translator", ex);
}
}
else {
this.customSqlExceptionTranslator = null;
}
}
public void setCustomSqlExceptionTranslator(SQLExceptionTranslator customSqlExceptionTranslator) {
this.customSqlExceptionTranslator = customSqlExceptionTranslator;
}
public SQLExceptionTranslator getCustomSqlExceptionTranslator() {
return this.customSqlExceptionTranslator;
}
}

12
spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodesFactory.java

@ -17,7 +17,6 @@ @@ -17,7 +17,6 @@
package org.springframework.jdbc.support;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import javax.sql.DataSource;
@ -171,7 +170,7 @@ public class SQLErrorCodesFactory { @@ -171,7 +170,7 @@ public class SQLErrorCodesFactory {
}
}
if (sec != null) {
checkSqlExceptionTranslatorRegistry(dbName, sec);
checkCustomTranslatorRegistry(dbName, sec);
if (logger.isDebugEnabled()) {
logger.debug("SQL error codes for '" + dbName + "' found");
}
@ -248,10 +247,12 @@ public class SQLErrorCodesFactory { @@ -248,10 +247,12 @@ public class SQLErrorCodesFactory {
}
}
private void checkSqlExceptionTranslatorRegistry(String dbName, SQLErrorCodes dbCodes) {
// Check the custom sql exception translator registry for any entries
/**
* Check the {@link CustomSQLExceptionTranslatorRegistry} for any entries.
*/
private void checkCustomTranslatorRegistry(String dbName, SQLErrorCodes dbCodes) {
SQLExceptionTranslator customTranslator =
CustomSQLExceptionTranslatorRegistry.getInstance().findSqlExceptionTranslatorForDatabase(dbName);
CustomSQLExceptionTranslatorRegistry.getInstance().findTranslatorForDatabase(dbName);
if (customTranslator != null) {
if (dbCodes.getCustomSqlExceptionTranslator() != null) {
logger.warn("Overriding already defined custom translator '" +
@ -265,7 +266,6 @@ public class SQLErrorCodesFactory { @@ -265,7 +266,6 @@ public class SQLErrorCodesFactory {
}
dbCodes.setCustomSqlExceptionTranslator(customTranslator);
}
}
}

2
spring-jdbc/src/test/resources/org/springframework/jdbc/support/test-custom-translators-context.xml

@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
<jdbc:embedded-database id="dataSource" type="H2"/>
<bean class="org.springframework.jdbc.support.CustomSQLExceptionTranslatorRegistrar">
<property name="sqlExceptionTranslators">
<property name="translators">
<map>
<entry key="H2">
<bean class="org.springframework.jdbc.support.CustomSqlExceptionTranslator"/>

9
spring-jms/src/main/java/org/springframework/jms/connection/JmsTransactionManager.java

@ -87,6 +87,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager @@ -87,6 +87,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
* @see TransactionAwareConnectionFactoryProxy
* @see org.springframework.jms.core.JmsTemplate
*/
@SuppressWarnings("serial")
public class JmsTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
@ -191,14 +192,6 @@ public class JmsTransactionManager extends AbstractPlatformTransactionManager @@ -191,14 +192,6 @@ public class JmsTransactionManager extends AbstractPlatformTransactionManager
getConnectionFactory(), txObject.getResourceHolder());
}
catch (JMSException ex) {
if (session != null) {
try {
session.close();
}
catch (Throwable ex2) {
// ignore
}
}
if (con != null) {
try {
con.close();

3
spring-web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java

@ -19,6 +19,7 @@ package org.springframework.web.context.support; @@ -19,6 +19,7 @@ package org.springframework.web.context.support;
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.AnnotationConfigUtils;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ScopeMetadataResolver;
import org.springframework.util.Assert;
@ -196,6 +197,8 @@ public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWe @@ -196,6 +197,8 @@ public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWe
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
beanFactory.registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);

25
spring-web/src/test/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContextTests.java

@ -19,9 +19,16 @@ package org.springframework.web.context.support; @@ -19,9 +19,16 @@ package org.springframework.web.context.support;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
/**
* @author Chris Beams
*/
@ -49,8 +56,24 @@ public class AnnotationConfigWebApplicationContextTests { @@ -49,8 +56,24 @@ public class AnnotationConfigWebApplicationContextTests {
assertNotNull(bean);
}
@Test
public void withBeanNameGenerator() {
AnnotationConfigWebApplicationContext ctx =
new AnnotationConfigWebApplicationContext();
ctx.setBeanNameGenerator(new AnnotationBeanNameGenerator() {
@Override
public String generateBeanName(BeanDefinition definition,
BeanDefinitionRegistry registry) {
return "custom-" + super.generateBeanName(definition, registry);
}
});
ctx.setConfigLocation(Config.class.getName());
ctx.refresh();
assertThat(ctx.containsBean("custom-myConfig"), is(true));
}
@Configuration
@Configuration("myConfig")
static class Config {
@Bean
public TestBean myTestBean() {

6
spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolver.java

@ -61,8 +61,10 @@ public class ServletResponseMethodArgumentResolver implements HandlerMethodArgum @@ -61,8 +61,10 @@ public class ServletResponseMethodArgumentResolver implements HandlerMethodArgum
MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
throws IOException {
mavContainer.setRequestHandled(true);
if (mavContainer != null) {
mavContainer.setRequestHandled(true);
}
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
Class<?> paramType = parameter.getParameterType();

10
spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolverTests.java

@ -70,6 +70,16 @@ public class ServletResponseMethodArgumentResolverTests { @@ -70,6 +70,16 @@ public class ServletResponseMethodArgumentResolverTests {
assertTrue(mavContainer.isRequestHandled());
}
// SPR-8983
public void servletResponseNoMavContainer() throws Exception {
MethodParameter servletResponseParameter = new MethodParameter(method, 0);
assertTrue("ServletResponse not supported", resolver.supportsParameter(servletResponseParameter));
Object result = resolver.resolveArgument(servletResponseParameter, null, webRequest, null);
assertSame("Invalid result", servletResponse, result);
}
@Test
public void outputStream() throws Exception {
MethodParameter outputStreamParameter = new MethodParameter(method, 1);

7
src/dist/changelog.txt vendored

@ -3,7 +3,7 @@ SPRING FRAMEWORK CHANGELOG @@ -3,7 +3,7 @@ SPRING FRAMEWORK CHANGELOG
http://www.springsource.org
Changes in version 3.1.1 (2012-02-13)
Changes in version 3.1.1 (2012-02-15)
-------------------------------------
* official support for Hibernate 4.0 GA as well as Hibernate 4.1
@ -13,9 +13,12 @@ Changes in version 3.1.1 (2012-02-13) @@ -13,9 +13,12 @@ Changes in version 3.1.1 (2012-02-13)
* @ActiveProfiles mechanism in test context framework works with @ImportResource as well
* context:property-placeholder's "file-encoding" attribute value is being applied correctly
* clarified Resource's "getFilename" method to return null if resource type does not have a filename
* Resource "contentLength()" implementations work with OSGi bundle resources and JBoss VFS resources
* PathMatchingResourcePatternResolver preserves caching for JNLP (Java Web Start) jar connections
* optimized converter lookup in GenericConversionService to avoid contention in JDK proxy check
* DataBinder correctly handles ParseException from Formatter for String->String case
* CacheNamespaceHandler actually parses cache:annotation-driven's "key-generator" attribute
* introduced CustomSQLExceptionTranslatorRegistry/Registrar for JDBC error code translation
* officially deprecated TopLinkJpaDialect in favor of EclipseLink and Spring's EclipseLinkJpaDialect
* fixed LocalContainerEntityManagerFactoryBean's "packagesToScan" to avoid additional provider scan
* LocalContainerEntityManagerFactoryBean's "persistenceUnitName" applies to "packagesToScan" as well
@ -28,7 +31,7 @@ Changes in version 3.1.1 (2012-02-13) @@ -28,7 +31,7 @@ Changes in version 3.1.1 (2012-02-13)
* added "entityInterceptor" property to Hibernate 4 LocalSessionFactoryBean
* added "getConfiguration" accessor to Hibernate 4 LocalSessionFactoryBean
* added "durability" and "description" properties to JobDetailFactoryBean
* corrected fix for QuartzJobBean to work with Quartz 2.0/2.1
* fixed QuartzJobBean and MethodInvokingJobDetailFactoryBean for compatibility with Quartz 2.0/2.1
* JMS CachingConnectionFactory never caches consumers for temporary queues and topics
* JMS SimpleMessageListenerContainer silently falls back to lazy registration of consumers
* Servlet/PortletContextResource's "isReadable()" implementation returns false for directories

Loading…
Cancel
Save