diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotatedGenericBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotatedGenericBeanDefinition.java index 5f4ee7f555..f0fd4c5cac 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotatedGenericBeanDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AnnotatedGenericBeanDefinition.java @@ -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; 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; * 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; } } diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/MethodInvokingJobDetailFactoryBean.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/MethodInvokingJobDetailFactoryBean.java index dd71eef9a1..80ce225457 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/MethodInvokingJobDetailFactoryBean.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/MethodInvokingJobDetailFactoryBean.java @@ -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 @@ 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; 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 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 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 @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) { diff --git a/spring-context/src/main/java/org/springframework/context/annotation/AdviceModeImportSelector.java b/spring-context/src/main/java/org/springframework/context/annotation/AdviceModeImportSelector.java index 8c4651bc37..eae51ec251 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/AdviceModeImportSelector.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/AdviceModeImportSelector.java @@ -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; 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*} diff --git a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java index 914b9d9ce7..d147a50656 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java @@ -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 public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) { this.reader.setBeanNameGenerator(beanNameGenerator); this.scanner.setBeanNameGenerator(beanNameGenerator); + this.getBeanFactory().registerSingleton( + AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator); } /** diff --git a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java index d184aa9b00..793ba314b4 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java @@ -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; 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 { 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 { return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass); } + } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationScopeMetadataResolver.java b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationScopeMetadataResolver.java index 0d655830b3..493745bd82 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationScopeMetadataResolver.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationScopeMetadataResolver.java @@ -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; 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. diff --git a/spring-context/src/main/java/org/springframework/context/annotation/AspectJAutoProxyRegistrar.java b/spring-context/src/main/java/org/springframework/context/annotation/AspectJAutoProxyRegistrar.java index b41fa7da25..aedbbbe28e 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/AspectJAutoProxyRegistrar.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/AspectJAutoProxyRegistrar.java @@ -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} diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java index 04a249566d..2afeba197e 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java @@ -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; diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java index 20729b0c5b..f0826a62eb 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java @@ -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 { /** * The {@link BeanNameGenerator} class to be used for naming detected components * within the Spring container. + *
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.
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java
index 9fa82e40c7..a549b8d0af 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java
@@ -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 {
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) {
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java
index ffa0e08d82..02b4125e61 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java
@@ -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;
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;
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;
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 {
private final Environment environment;
+ private final BeanNameGenerator beanNameGenerator;
+
/**
* Create a new {@link ConfigurationClassBeanDefinitionReader} instance that will be used
@@ -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 {
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 Note that this strategy does not apply to {@link Bean} methods.
+ * 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
+ * This class does not load the bean This class does not 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 scanned 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;
diff --git a/spring-context/src/test/java/org/springframework/context/annotation/AsmCircularImportDetectionTests.java b/spring-context/src/test/java/org/springframework/context/annotation/AsmCircularImportDetectionTests.java
index 17b232da59..36a9b1eed8 100644
--- a/spring-context/src/test/java/org/springframework/context/annotation/AsmCircularImportDetectionTests.java
+++ b/spring-context/src/test/java/org/springframework/context/annotation/AsmCircularImportDetectionTests.java
@@ -40,6 +40,7 @@ public class AsmCircularImportDetectionTests extends AbstractCircularImportDetec
new FailFastProblemReporter(),
new StandardEnvironment(),
new DefaultResourceLoader(),
+ new AnnotationBeanNameGenerator(),
new DefaultListableBeanFactory());
}
diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ImportAwareTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ImportAwareTests.java
index 180176452b..822923d9c1 100644
--- a/spring-context/src/test/java/org/springframework/context/annotation/ImportAwareTests.java
+++ b/spring-context/src/test/java/org/springframework/context/annotation/ImportAwareTests.java
@@ -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;
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.
diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationBeanNameTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationBeanNameTests.java
new file mode 100644
index 0000000000..445397c384
--- /dev/null
+++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationBeanNameTests.java
@@ -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"; }
+ }
+}
diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationMetaAnnotationTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationMetaAnnotationTests.java
new file mode 100644
index 0000000000..c556e86898
--- /dev/null
+++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationMetaAnnotationTests.java
@@ -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 "";
+ }
+}
diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/spr8955/Spr8955Parent.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/spr8955/Spr8955Parent.java
new file mode 100644
index 0000000000..21a1b007df
--- /dev/null
+++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/spr8955/Spr8955Parent.java
@@ -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 {
+
+ }
+
+}
diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/spr8955/Spr8955Tests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/spr8955/Spr8955Tests.java
new file mode 100644
index 0000000000..c8b6fa4dea
--- /dev/null
+++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/spr8955/Spr8955Tests.java
@@ -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();
+ }
+
+}
diff --git a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java
index f5c5f18034..e1f796847a 100644
--- a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java
+++ b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java
@@ -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 {
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 {
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");
}
diff --git a/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java b/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java
index 2f6c8e7d7d..1d48f7fb33 100644
--- a/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java
+++ b/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java
@@ -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) {
+ }
+ }
}
/**
diff --git a/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java b/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java
index d96ba7c75b..3d0805c345 100644
--- a/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java
+++ b/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java
@@ -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
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.
diff --git a/spring-core/src/main/java/org/springframework/core/io/UrlResource.java b/spring-core/src/main/java/org/springframework/core/io/UrlResource.java
index a68e919c66..2f9f162d78 100644
--- a/spring-core/src/main/java/org/springframework/core/io/UrlResource.java
+++ b/spring-core/src/main/java/org/springframework/core/io/UrlResource.java
@@ -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;
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 {
*/
public InputStream getInputStream() throws IOException {
URLConnection con = this.url.openConnection();
- con.setUseCaches(false);
+ ResourceUtils.useCachesIfNecessary(con);
try {
return con.getInputStream();
}
diff --git a/spring-core/src/main/java/org/springframework/core/io/VfsResource.java b/spring-core/src/main/java/org/springframework/core/io/VfsResource.java
index c161858ad6..88925f6b78 100644
--- a/spring-core/src/main/java/org/springframework/core/io/VfsResource.java
+++ b/spring-core/src/main/java/org/springframework/core/io/VfsResource.java
@@ -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);
diff --git a/spring-core/src/main/java/org/springframework/core/io/VfsUtils.java b/spring-core/src/main/java/org/springframework/core/io/VfsUtils.java
index a0e268ce70..71c2ceb097 100644
--- a/spring-core/src/main/java/org/springframework/core/io/VfsUtils.java
+++ b/spring-core/src/main/java/org/springframework/core/io/VfsUtils.java
@@ -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;
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 {
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 {
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 {
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 {
}
}
+ 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);
}
diff --git a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java
index a9d473da2a..f9a3645a3e 100644
--- a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java
+++ b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java
@@ -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
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();
diff --git a/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderUtils.java b/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderUtils.java
index f52c0f04f7..20b74d017a 100644
--- a/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderUtils.java
+++ b/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderUtils.java
@@ -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;
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 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 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 Not public to enforce Singleton design pattern.
*/
private 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 Class early.
+ * java.util.Properties,
@@ -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);
}
diff --git a/spring-core/src/main/java/org/springframework/util/ResourceUtils.java b/spring-core/src/main/java/org/springframework/util/ResourceUtils.java
index e309719029..b9dc3bd855 100644
--- a/spring-core/src/main/java/org/springframework/util/ResourceUtils.java
+++ b/spring-core/src/main/java/org/springframework/util/ResourceUtils.java
@@ -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;
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 {
return new URI(StringUtils.replace(location, " ", "%20"));
}
+ /**
+ * Set the {@link URLConnection#setUseCaches "useCaches"} flag on the
+ * given connection, preferring false but leaving the
+ * flag at true 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"));
+ }
+
}
diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/CustomSQLExceptionTranslatorRegistrar.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/CustomSQLExceptionTranslatorRegistrar.java
index e9806b8c0b..0d15a87025 100644
--- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/CustomSQLExceptionTranslatorRegistrar.java
+++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/CustomSQLExceptionTranslatorRegistrar.java
@@ -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 Mapsql-error-codes.xml file.
+ * null if none found
+ */
+ public SQLExceptionTranslator findTranslatorForDatabase(String dbName) {
+ return this.translatorMap.get(dbName);
}
}
diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java
index 8dde372bec..c82bbad5bf 100644
--- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java
+++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java
@@ -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 {
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 {
private CustomSQLErrorCodesTranslation[] customTranslations;
+ private SQLExceptionTranslator customSqlExceptionTranslator;
+
/**
* Set this property if the database name contains spaces,
@@ -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 {
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;
+ }
+
}
diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodesFactory.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodesFactory.java
index bdaf16c0e1..a127e82937 100644
--- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodesFactory.java
+++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodesFactory.java
@@ -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 {
}
}
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 {
}
}
- 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 {
}
dbCodes.setCustomSqlExceptionTranslator(customTranslator);
}
-
}
}
diff --git a/spring-jdbc/src/test/resources/org/springframework/jdbc/support/test-custom-translators-context.xml b/spring-jdbc/src/test/resources/org/springframework/jdbc/support/test-custom-translators-context.xml
index df3a6258da..5603f4bd0a 100644
--- a/spring-jdbc/src/test/resources/org/springframework/jdbc/support/test-custom-translators-context.xml
+++ b/spring-jdbc/src/test/resources/org/springframework/jdbc/support/test-custom-translators-context.xml
@@ -8,7 +8,7 @@