Supports both transactional and non-transactional DataSource access. * With a non-XA DataSource and local Spring transactions, a single DataSource @@ -58,6 +59,8 @@ import org.springframework.lang.Nullable; * @since 1.1 * @see SchedulerFactoryBean#setDataSource * @see SchedulerFactoryBean#setNonTransactionalDataSource + * @see SchedulerFactoryBean#getConfigTimeDataSource() + * @see SchedulerFactoryBean#getConfigTimeNonTransactionalDataSource() * @see org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection * @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection */ diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java index e0982a2e5ff..15185bba6c3 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java @@ -310,9 +310,11 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe /** * Set the default {@link DataSource} to be used by the Scheduler. - * If set, this will override corresponding settings in Quartz properties. *
Note: If this is set, the Quartz settings should not define * a job store "dataSource" to avoid meaningless double configuration. + * Also, do not define a "org.quartz.jobStore.class" property at all. + * (You may explicitly define Spring's {@link LocalDataSourceJobStore} + * but that's the default when using this method anyway.) *
A Spring-specific subclass of Quartz' JobStoreCMT will be used.
* It is therefore strongly recommended to perform all operations on
* the Scheduler within Spring-managed (or plain JTA) transactions.
diff --git a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
index 1bb789a46e9..17bc9a7330e 100644
--- a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
+++ b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
@@ -1309,6 +1309,16 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
return getBeanFactory().findAnnotationOnBean(beanName, annotationType);
}
+ @Override
+ @Nullable
+ public A findAnnotationOnBean(
+ String beanName, Class annotationType, boolean allowFactoryBeanInit)
+ throws NoSuchBeanDefinitionException {
+
+ assertBeanFactoryActive();
+ return getBeanFactory().findAnnotationOnBean(beanName, annotationType, allowFactoryBeanInit);
+ }
+
//---------------------------------------------------------------------
// Implementation of HierarchicalBeanFactory interface
diff --git a/spring-context/src/test/java/org/springframework/aop/framework/ProxyFactoryBeanTests.java b/spring-context/src/test/java/org/springframework/aop/framework/ProxyFactoryBeanTests.java
index 57df369b68e..91d85d35dad 100644
--- a/spring-context/src/test/java/org/springframework/aop/framework/ProxyFactoryBeanTests.java
+++ b/spring-context/src/test/java/org/springframework/aop/framework/ProxyFactoryBeanTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2021 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.
@@ -65,10 +65,10 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIOException;
/**
- * @since 13.03.2003
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
+ * @since 13.03.2003
*/
public class ProxyFactoryBeanTests {
@@ -633,20 +633,50 @@ public class ProxyFactoryBeanTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource(FROZEN_CONTEXT, CLASS));
- Advised advised = (Advised)bf.getBean("frozen");
+ Advised advised = (Advised) bf.getBean("frozen");
assertThat(advised.isFrozen()).as("The proxy should be frozen").isTrue();
}
@Test
- public void testDetectsInterfaces() throws Exception {
+ public void testDetectsInterfaces() {
ProxyFactoryBean fb = new ProxyFactoryBean();
fb.setTarget(new TestBean());
fb.addAdvice(new DebugInterceptor());
fb.setBeanFactory(new DefaultListableBeanFactory());
+
ITestBean proxy = (ITestBean) fb.getObject();
assertThat(AopUtils.isJdkDynamicProxy(proxy)).isTrue();
}
+ @Test
+ public void testWithInterceptorNames() {
+ DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
+ bf.registerSingleton("debug", new DebugInterceptor());
+
+ ProxyFactoryBean fb = new ProxyFactoryBean();
+ fb.setTarget(new TestBean());
+ fb.setInterceptorNames("debug");
+ fb.setBeanFactory(bf);
+
+ Advised proxy = (Advised) fb.getObject();
+ assertThat(proxy.getAdvisorCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void testWithLateInterceptorNames() {
+ DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
+ bf.registerSingleton("debug", new DebugInterceptor());
+
+ ProxyFactoryBean fb = new ProxyFactoryBean();
+ fb.setTarget(new TestBean());
+ fb.setBeanFactory(bf);
+ fb.getObject();
+
+ fb.setInterceptorNames("debug");
+ Advised proxy = (Advised) fb.getObject();
+ assertThat(proxy.getAdvisorCount()).isEqualTo(1);
+ }
+
/**
* Fires only on void methods. Saves list of methods intercepted.
diff --git a/spring-context/src/test/java/org/springframework/cache/config/EnableCachingIntegrationTests.java b/spring-context/src/test/java/org/springframework/cache/config/EnableCachingIntegrationTests.java
index f9154f4776f..39a636298eb 100644
--- a/spring-context/src/test/java/org/springframework/cache/config/EnableCachingIntegrationTests.java
+++ b/spring-context/src/test/java/org/springframework/cache/config/EnableCachingIntegrationTests.java
@@ -96,6 +96,19 @@ public class EnableCachingIntegrationTests {
assertCacheHit(key, value, cache);
}
+ @Test
+ public void barServiceWithCacheableInterfaceCglib() {
+ this.context = new AnnotationConfigApplicationContext(BarConfigCglib.class);
+ BarService service = this.context.getBean(BarService.class);
+ Cache cache = getCache();
+
+ Object key = new Object();
+ assertCacheMiss(key, cache);
+
+ Object value = service.getSimple(key);
+ assertCacheHit(key, value, cache);
+ }
+
@Test
public void beanConditionOff() {
this.context = new AnnotationConfigApplicationContext(BeanConditionConfig.class);
@@ -223,6 +236,36 @@ public class EnableCachingIntegrationTests {
}
}
+ @Configuration
+ @Import(SharedConfig.class)
+ @EnableCaching(proxyTargetClass = true)
+ static class BarConfigCglib {
+
+ @Bean
+ public BarService barService() {
+ return new BarServiceImpl();
+ }
+ }
+
+
+ interface BarService {
+
+ @Cacheable(cacheNames = "testCache")
+ Object getSimple(Object key);
+ }
+
+
+ static class BarServiceImpl implements BarService {
+
+ private final AtomicLong counter = new AtomicLong();
+
+ @Override
+ public Object getSimple(Object key) {
+ return this.counter.getAndIncrement();
+ }
+ }
+
+
@Configuration
@Import(FooConfig.class)
@EnableCaching
diff --git a/spring-context/src/test/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBeanTests.java b/spring-context/src/test/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBeanTests.java
index d350341a8c4..8f81b987c8a 100644
--- a/spring-context/src/test/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBeanTests.java
+++ b/spring-context/src/test/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBeanTests.java
@@ -76,6 +76,7 @@ class ThreadPoolExecutorFactoryBeanTests {
verify(threadPoolExecutor).prestartAllCoreThreads();
}
+
@Configuration
static class ExecutorConfig {
@@ -83,9 +84,10 @@ class ThreadPoolExecutorFactoryBeanTests {
ThreadPoolExecutorFactoryBean executor() {
return new ThreadPoolExecutorFactoryBean();
}
-
}
+
+ @SuppressWarnings("serial")
private static class TestThreadPoolExecutorFactoryBean extends ThreadPoolExecutorFactoryBean {
@Override
diff --git a/spring-core/src/main/java/org/springframework/core/log/LogFormatUtils.java b/spring-core/src/main/java/org/springframework/core/log/LogFormatUtils.java
index 9a2693e2ce6..550a202255c 100644
--- a/spring-core/src/main/java/org/springframework/core/log/LogFormatUtils.java
+++ b/spring-core/src/main/java/org/springframework/core/log/LogFormatUtils.java
@@ -22,6 +22,7 @@ import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.springframework.lang.Nullable;
+import org.springframework.util.ObjectUtils;
/**
* Utility methods for formatting and logging messages.
@@ -71,10 +72,10 @@ public abstract class LogFormatUtils {
}
String result;
try {
- result = value.toString();
+ result = ObjectUtils.nullSafeToString(value);
}
catch (Throwable ex) {
- result = ex.toString();
+ result = ObjectUtils.nullSafeToString(ex);
}
if (maxLength != -1) {
result = (result.length() > maxLength ? result.substring(0, maxLength) + " (truncated)..." : result);
diff --git a/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java b/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java
index ba58532c74f..3ca17918b53 100644
--- a/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java
+++ b/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2021 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.
@@ -1159,6 +1159,20 @@ class ResolvableTypeTests {
assertThatResolvableType(complex4).isNotAssignableFrom(complex3);
}
+ @Test
+ void identifyTypeVariable() throws Exception {
+ Method method = ClassArguments.class.getMethod("typedArgumentFirst", Class.class, Class.class, Class.class);
+ ResolvableType returnType = ResolvableType.forMethodReturnType(method, ClassArguments.class);
+
+ ResolvableType arg0 = ResolvableType.forMethodParameter(method, 0, ClassArguments.class);
+ ResolvableType arg1 = ResolvableType.forMethodParameter(method, 1, ClassArguments.class);
+ ResolvableType arg2 = ResolvableType.forMethodParameter(method, 2, ClassArguments.class);
+
+ assertThat(returnType.getType().equals(arg0.as(Class.class).getGeneric(0).getType())).isTrue();
+ assertThat(returnType.getType().equals(arg1.as(Class.class).getGeneric(0).getType())).isFalse();
+ assertThat(returnType.getType().equals(arg2.as(Class.class).getGeneric(0).getType())).isFalse();
+ }
+
@Test
void hashCodeAndEquals() throws Exception {
ResolvableType forClass = ResolvableType.forClass(List.class);
@@ -1427,6 +1441,10 @@ class ResolvableTypeTests {
}
+ interface TypedMethods extends Methods