Compare commits

..

1 Commits

Author SHA1 Message Date
Spring Builds b02f4a06ca Release v5.3.28 2023-06-15 07:19:13 +00:00
86 changed files with 825 additions and 1388 deletions
+6 -6
View File
@@ -28,8 +28,8 @@ configure(allprojects) { project ->
dependencyManagement {
imports {
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.7"
mavenBom "io.netty:netty-bom:4.1.94.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.34"
mavenBom "io.netty:netty-bom:4.1.93.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.33"
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR13"
mavenBom "io.rsocket:rsocket-bom:1.1.3"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.51.v20230217"
@@ -128,18 +128,18 @@ configure(allprojects) { project ->
dependency "org.webjars:webjars-locator-core:0.48"
dependency "org.webjars:underscorejs:1.8.3"
dependencySet(group: 'org.apache.tomcat', version: '9.0.78') {
dependencySet(group: 'org.apache.tomcat', version: '9.0.75') {
entry 'tomcat-util'
entry('tomcat-websocket') {
exclude group: "org.apache.tomcat", name: "tomcat-servlet-api"
exclude group: "org.apache.tomcat", name: "tomcat-websocket-api"
}
}
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.78') {
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.75') {
entry 'tomcat-embed-core'
entry 'tomcat-embed-websocket'
}
dependencySet(group: 'io.undertow', version: '2.2.25.Final') {
dependencySet(group: 'io.undertow', version: '2.2.24.Final') {
entry 'undertow-core'
entry('undertow-servlet') {
exclude group: "org.jboss.spec.javax.servlet", name: "jboss-servlet-api_4.0_spec"
@@ -340,7 +340,7 @@ configure([rootProject] + javaProjects) { project ->
}
checkstyle {
toolVersion = "10.12.1"
toolVersion = "10.9.3"
configDirectory.set(rootProject.file("src/checkstyle"))
}
+1 -1
View File
@@ -1,4 +1,4 @@
FROM ubuntu:jammy-20230624
FROM ubuntu:focal-20220922
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
-2
View File
@@ -5,8 +5,6 @@ image_resource:
source:
repository: springio/github-changelog-generator
tag: '0.0.7'
username: ((docker-hub-username))
password: ((docker-hub-password))
inputs:
- name: git-repo
- name: artifactory-repo
-2
View File
@@ -5,8 +5,6 @@ image_resource:
source:
repository: springio/concourse-release-scripts
tag: '0.3.4'
username: ((docker-hub-username))
password: ((docker-hub-password))
inputs:
- name: git-repo
- name: artifactory-repo
+1 -1
View File
@@ -1,4 +1,4 @@
version=5.3.29
version=5.3.28
org.gradle.jvmargs=-Xmx2048m
org.gradle.caching=true
org.gradle.parallel=true
@@ -594,7 +594,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
* Resolve the specified cached method argument or field value.
*/
@Nullable
private Object resolveCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) {
private Object resolvedCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) {
if (cachedArgument instanceof DependencyDescriptor) {
DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument;
Assert.state(this.beanFactory != null, "No BeanFactory available");
@@ -629,12 +629,10 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
Object value;
if (this.cached) {
try {
value = resolveCachedArgument(beanName, this.cachedFieldValue);
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (BeansException ex) {
// Unexpected target bean mismatch for cached argument -> re-resolve
this.cached = false;
logger.debug("Failed to resolve cached argument", ex);
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
value = resolveFieldValue(field, bean, beanName);
}
}
@@ -663,8 +661,9 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
}
synchronized (this) {
if (!this.cached) {
Object cachedFieldValue = null;
if (value != null || this.required) {
Object cachedFieldValue = desc;
cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (value != null && autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
@@ -674,13 +673,9 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
desc, autowiredBeanName, field.getType());
}
}
this.cachedFieldValue = cachedFieldValue;
this.cached = true;
}
else {
this.cachedFieldValue = null;
// cached flag remains false
}
this.cachedFieldValue = cachedFieldValue;
this.cached = true;
}
}
return value;
@@ -714,12 +709,10 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
Object[] arguments;
if (this.cached) {
try {
arguments = resolveCachedArguments(beanName, this.cachedMethodArguments);
arguments = resolveCachedArguments(beanName);
}
catch (BeansException ex) {
// Unexpected target bean mismatch for cached argument -> re-resolve
this.cached = false;
logger.debug("Failed to resolve cached argument", ex);
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
arguments = resolveMethodArguments(method, bean, beanName);
}
}
@@ -738,13 +731,14 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
}
@Nullable
private Object[] resolveCachedArguments(@Nullable String beanName, @Nullable Object[] cachedMethodArguments) {
private Object[] resolveCachedArguments(@Nullable String beanName) {
Object[] cachedMethodArguments = this.cachedMethodArguments;
if (cachedMethodArguments == null) {
return null;
}
Object[] arguments = new Object[cachedMethodArguments.length];
for (int i = 0; i < arguments.length; i++) {
arguments[i] = resolveCachedArgument(beanName, cachedMethodArguments[i]);
arguments[i] = resolvedCachedArgument(beanName, cachedMethodArguments[i]);
}
return arguments;
}
@@ -777,7 +771,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
synchronized (this) {
if (!this.cached) {
if (arguments != null) {
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, argumentCount);
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
registerDependentBeans(beanName, autowiredBeans);
if (autowiredBeans.size() == argumentCount) {
Iterator<String> it = autowiredBeans.iterator();
@@ -792,12 +786,11 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
}
}
this.cachedMethodArguments = cachedMethodArguments;
this.cached = true;
}
else {
this.cachedMethodArguments = null;
// cached flag remains false
}
this.cached = true;
}
}
return arguments;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 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.
@@ -961,7 +961,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
@@ -447,17 +447,17 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
}
String canonicalName = canonicalName(beanName);
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans == null || dependentBeans.isEmpty()) {
if (dependentBeans == null) {
return false;
}
if (dependentBeans.contains(dependentBeanName)) {
return true;
}
if (alreadySeen == null) {
alreadySeen = new HashSet<>();
}
alreadySeen.add(beanName);
for (String transitiveDependency : dependentBeans) {
if (alreadySeen == null) {
alreadySeen = new HashSet<>();
}
alreadySeen.add(beanName);
if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 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.
@@ -506,12 +506,23 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
if (isExternallyManagedInitMethod(initMethod)) {
return true;
}
return hasAnyExternallyManagedMethod(this.externallyManagedInitMethods, initMethod);
if (this.externallyManagedInitMethods != null) {
for (String candidate : this.externallyManagedInitMethods) {
int indexOfDot = candidate.lastIndexOf('.');
if (indexOfDot >= 0) {
String methodName = candidate.substring(indexOfDot + 1);
if (methodName.equals(initMethod)) {
return true;
}
}
}
}
return false;
}
}
/**
* Get all externally managed initialization methods (as an immutable Set).
* Return all externally managed initialization methods (as an immutable Set).
* <p>See {@link #registerExternallyManagedInitMethod} for details
* regarding the format for the initialization methods in the returned set.
* @since 5.3.11
@@ -572,23 +583,19 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
if (isExternallyManagedDestroyMethod(destroyMethod)) {
return true;
}
return hasAnyExternallyManagedMethod(this.externallyManagedDestroyMethods, destroyMethod);
}
}
private static boolean hasAnyExternallyManagedMethod(Set<String> candidates, String methodName) {
if (candidates != null) {
for (String candidate : candidates) {
int indexOfDot = candidate.lastIndexOf('.');
if (indexOfDot > 0) {
String candidateMethodName = candidate.substring(indexOfDot + 1);
if (candidateMethodName.equals(methodName)) {
return true;
if (this.externallyManagedDestroyMethods != null) {
for (String candidate : this.externallyManagedDestroyMethods) {
int indexOfDot = candidate.lastIndexOf('.');
if (indexOfDot >= 0) {
String methodName = candidate.substring(indexOfDot + 1);
if (methodName.equals(destroyMethod)) {
return true;
}
}
}
}
return false;
}
return false;
}
/**
@@ -124,11 +124,11 @@ public class AutowiredAnnotationBeanPostProcessorTests {
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
ResourceInjectionBean bean = bf.getBean("annotatedBean", ResourceInjectionBean.class);
ResourceInjectionBean bean = (ResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
bean = bf.getBean("annotatedBean", ResourceInjectionBean.class);
bean = (ResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
}
@@ -142,66 +142,12 @@ public class AutowiredAnnotationBeanPostProcessorTests {
tb.setFactoryMethodName("createTestBean");
bf.registerBeanDefinition("testBean", tb);
@SuppressWarnings("rawtypes")
NonPublicResourceInjectionBean bean = bf.getBean("annotatedBean", NonPublicResourceInjectionBean.class);
NonPublicResourceInjectionBean bean = (NonPublicResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
bean = bf.getBean("annotatedBean", NonPublicResourceInjectionBean.class);
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
}
@Test
void resourceInjectionWithSometimesNullBean() {
RootBeanDefinition bd = new RootBeanDefinition(OptionalResourceInjectionBean.class);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
RootBeanDefinition tb = new RootBeanDefinition(SometimesNullFactoryMethods.class);
tb.setFactoryMethodName("createTestBean");
tb.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("testBean", tb);
SometimesNullFactoryMethods.active = false;
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
SometimesNullFactoryMethods.active = true;
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNotNull();
assertThat(bean.getTestBean2()).isNotNull();
assertThat(bean.getTestBean3()).isNotNull();
SometimesNullFactoryMethods.active = false;
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
SometimesNullFactoryMethods.active = false;
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
SometimesNullFactoryMethods.active = true;
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNotNull();
assertThat(bean.getTestBean2()).isNotNull();
assertThat(bean.getTestBean3()).isNotNull();
SometimesNullFactoryMethods.active = true;
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNotNull();
assertThat(bean.getTestBean2()).isNotNull();
assertThat(bean.getTestBean3()).isNotNull();
SometimesNullFactoryMethods.active = false;
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
bean = (NonPublicResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
@@ -217,7 +163,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
NestedTestBean ntb = new NestedTestBean();
bf.registerSingleton("nestedTestBean", ntb);
TypedExtendedResourceInjectionBean bean = bf.getBean("annotatedBean", TypedExtendedResourceInjectionBean.class);
TypedExtendedResourceInjectionBean bean = (TypedExtendedResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -225,7 +171,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getNestedTestBean()).isSameAs(ntb);
assertThat(bean.getBeanFactory()).isSameAs(bf);
bean = bf.getBean("annotatedBean", TypedExtendedResourceInjectionBean.class);
bean = (TypedExtendedResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -247,7 +193,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerSingleton("nestedTestBean", ntb);
TestBean tb = bf.getBean("testBean", TestBean.class);
TypedExtendedResourceInjectionBean bean = bf.getBean("annotatedBean", TypedExtendedResourceInjectionBean.class);
TypedExtendedResourceInjectionBean bean = (TypedExtendedResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -274,7 +220,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
NestedTestBean ntb = new NestedTestBean();
bf.registerSingleton("nestedTestBean", ntb);
TypedExtendedResourceInjectionBean bean = bf.getBean("annotatedBean", TypedExtendedResourceInjectionBean.class);
TypedExtendedResourceInjectionBean bean = (TypedExtendedResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb2);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -292,7 +238,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
NestedTestBean ntb = new NestedTestBean();
bf.registerSingleton("nestedTestBean", ntb);
OverriddenExtendedResourceInjectionBean bean = bf.getBean("annotatedBean", OverriddenExtendedResourceInjectionBean.class);
OverriddenExtendedResourceInjectionBean bean = (OverriddenExtendedResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -312,7 +258,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
NestedTestBean ntb = new NestedTestBean();
bf.registerSingleton("nestedTestBean", ntb);
DefaultMethodResourceInjectionBean bean = bf.getBean("annotatedBean", DefaultMethodResourceInjectionBean.class);
DefaultMethodResourceInjectionBean bean = (DefaultMethodResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -335,7 +281,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
NestedTestBean ntb = new NestedTestBean();
bf.registerSingleton("nestedTestBean", ntb);
TypedExtendedResourceInjectionBean bean = bf.getBean("annotatedBean", TypedExtendedResourceInjectionBean.class);
TypedExtendedResourceInjectionBean bean = (TypedExtendedResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -356,7 +302,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
NestedTestBean ntb2 = new NestedTestBean();
bf.registerSingleton("nestedTestBean2", ntb2);
OptionalResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -384,7 +330,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
NestedTestBean ntb2 = new NestedTestBean();
bf.registerSingleton("nestedTestBean2", ntb2);
OptionalResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -399,7 +345,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.destroySingleton("testBean");
bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
@@ -414,7 +360,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerSingleton("testBean", tb);
bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -441,7 +387,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
NestedTestBean ntb2 = new NestedTestBean();
bf.registerSingleton("nestedTestBean2", ntb2);
OptionalResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
assertThat(bean.getTestBean2()).isSameAs(bf.getBean("testBean"));
assertThat(bean.getTestBean3()).isSameAs(bf.getBean("testBean"));
@@ -456,7 +402,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.removeBeanDefinition("testBean");
bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
@@ -471,7 +417,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
assertThat(bean.getTestBean2()).isSameAs(bf.getBean("testBean"));
assertThat(bean.getTestBean3()).isSameAs(bf.getBean("testBean"));
@@ -500,8 +446,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerSingleton("nestedTestBean2", ntb2);
// Two calls to verify that caching doesn't break re-creation.
OptionalCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
OptionalCollectionResourceInjectionBean bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -531,8 +477,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerSingleton("nestedTestBean1", ntb1);
// Two calls to verify that caching doesn't break re-creation.
OptionalCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
OptionalCollectionResourceInjectionBean bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -552,7 +498,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
OptionalResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -564,7 +510,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public void testOptionalResourceInjectionWithNoDependencies() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalResourceInjectionBean.class));
OptionalResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
@@ -586,7 +532,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
ntb2.setOrder(1);
bf.registerSingleton("nestedTestBean2", ntb2);
OptionalResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -612,7 +558,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
FixedOrder1NestedTestBean ntb2 = new FixedOrder1NestedTestBean();
bf.registerSingleton("nestedTestBean2", ntb2);
OptionalResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -643,8 +589,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerSingleton("nestedTestBean2", ntb2);
// Two calls to verify that caching doesn't break re-creation.
OptionalCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
OptionalCollectionResourceInjectionBean bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -676,8 +622,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerSingleton("nestedTestBean2", ntb2);
// Two calls to verify that caching doesn't break re-creation.
OptionalCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
OptionalCollectionResourceInjectionBean bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -704,7 +650,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
NestedTestBean ntb = new NestedTestBean();
bf.registerSingleton("nestedTestBean", ntb);
ConstructorResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -712,7 +658,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getNestedTestBean()).isSameAs(ntb);
assertThat(bean.getBeanFactory()).isSameAs(bf);
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -731,7 +677,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
NestedTestBean ntb = new NestedTestBean();
bf.registerSingleton("nestedTestBean", ntb);
ConstructorResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -741,7 +687,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.destroySingleton("nestedTestBean");
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -751,7 +697,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerSingleton("nestedTestBean", ntb);
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -769,7 +715,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerSingleton("testBean", tb);
bf.registerBeanDefinition("nestedTestBean", new RootBeanDefinition(NestedTestBean.class));
ConstructorResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -779,7 +725,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.removeBeanDefinition("nestedTestBean");
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -789,7 +735,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("nestedTestBean", new RootBeanDefinition(NestedTestBean.class));
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -808,7 +754,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("nestedTestBean", new RootBeanDefinition(NullNestedTestBeanFactoryBean.class));
bf.registerSingleton("nestedTestBean2", new NestedTestBean());
ConstructorResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -816,7 +762,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getNestedTestBean()).isNull();
assertThat(bean.getBeanFactory()).isSameAs(bf);
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getTestBean2()).isSameAs(tb);
assertThat(bean.getTestBean3()).isSameAs(tb);
@@ -838,7 +784,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("nestedTestBean", ntb);
bf.registerSingleton("nestedTestBean2", new NestedTestBean());
ConstructorResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
@@ -846,7 +792,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertThat(bean.getNestedTestBean()).isNull();
assertThat(bean.getBeanFactory()).isSameAs(bf);
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isNull();
assertThat(bean.getTestBean2()).isNull();
assertThat(bean.getTestBean3()).isNull();
@@ -865,7 +811,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
NestedTestBean ntb2 = new NestedTestBean();
bf.registerSingleton("nestedTestBean2", ntb2);
ConstructorsResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsResourceInjectionBean.class);
ConstructorsResourceInjectionBean bean = (ConstructorsResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNull();
assertThat(bean.getTestBean4()).isSameAs(tb);
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
@@ -876,8 +822,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
@Test
public void testConstructorResourceInjectionWithNoCandidatesAndNoFallback() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ConstructorWithoutFallbackBean.class));
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
.isThrownBy(() -> bf.getBean("annotatedBean"))
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() ->
bf.getBean("annotatedBean"))
.satisfies(methodParameterDeclaredOn(ConstructorWithoutFallbackBean.class));
}
@@ -891,7 +837,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
NestedTestBean ntb2 = new NestedTestBean();
bf.registerSingleton("nestedTestBean2", ntb2);
ConstructorsCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsCollectionResourceInjectionBean.class);
ConstructorsCollectionResourceInjectionBean bean = (ConstructorsCollectionResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNull();
assertThat(bean.getTestBean4()).isSameAs(tb);
assertThat(bean.getNestedTestBeans().size()).isEqualTo(1);
@@ -913,7 +859,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
NestedTestBean ntb2 = new NestedTestBean();
bf.registerSingleton("nestedTestBean2", ntb2);
ConstructorsCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsCollectionResourceInjectionBean.class);
ConstructorsCollectionResourceInjectionBean bean = (ConstructorsCollectionResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNull();
assertThat(bean.getTestBean4()).isSameAs(tb);
assertThat(bean.getNestedTestBeans().size()).isEqualTo(2);
@@ -931,7 +877,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
FixedOrder1NestedTestBean ntb2 = new FixedOrder1NestedTestBean();
bf.registerSingleton("nestedTestBean2", ntb2);
ConstructorsResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsResourceInjectionBean.class);
ConstructorsResourceInjectionBean bean = (ConstructorsResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNull();
assertThat(bean.getTestBean4()).isSameAs(tb);
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
@@ -949,7 +895,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
FixedOrder1NestedTestBean ntb2 = new FixedOrder1NestedTestBean();
bf.registerSingleton("nestedTestBean2", ntb2);
ConstructorsCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsCollectionResourceInjectionBean.class);
ConstructorsCollectionResourceInjectionBean bean = (ConstructorsCollectionResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNull();
assertThat(bean.getTestBean4()).isSameAs(tb);
assertThat(bean.getNestedTestBeans().size()).isEqualTo(2);
@@ -967,7 +913,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
FixedOrder1NestedTestBean ntb2 = new FixedOrder1NestedTestBean();
bf.registerSingleton("nestedTestBean2", ntb2);
SingleConstructorVarargBean bean = bf.getBean("annotatedBean", SingleConstructorVarargBean.class);
SingleConstructorVarargBean bean = (SingleConstructorVarargBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getNestedTestBeans().size()).isEqualTo(2);
assertThat(bean.getNestedTestBeans().get(0)).isSameAs(ntb2);
@@ -980,7 +926,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
SingleConstructorVarargBean bean = bf.getBean("annotatedBean", SingleConstructorVarargBean.class);
SingleConstructorVarargBean bean = (SingleConstructorVarargBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getNestedTestBeans()).isNotNull();
assertThat(bean.getNestedTestBeans().isEmpty()).isTrue();
@@ -996,7 +942,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
FixedOrder1NestedTestBean ntb2 = new FixedOrder1NestedTestBean();
bf.registerSingleton("nestedTestBean2", ntb2);
SingleConstructorRequiredCollectionBean bean = bf.getBean("annotatedBean", SingleConstructorRequiredCollectionBean.class);
SingleConstructorRequiredCollectionBean bean = (SingleConstructorRequiredCollectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getNestedTestBeans().size()).isEqualTo(2);
assertThat(bean.getNestedTestBeans().get(0)).isSameAs(ntb2);
@@ -1009,7 +955,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
SingleConstructorRequiredCollectionBean bean = bf.getBean("annotatedBean", SingleConstructorRequiredCollectionBean.class);
SingleConstructorRequiredCollectionBean bean = (SingleConstructorRequiredCollectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getNestedTestBeans()).isNotNull();
assertThat(bean.getNestedTestBeans().isEmpty()).isTrue();
@@ -1025,7 +971,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
FixedOrder1NestedTestBean ntb2 = new FixedOrder1NestedTestBean();
bf.registerSingleton("nestedTestBean2", ntb2);
SingleConstructorOptionalCollectionBean bean = bf.getBean("annotatedBean", SingleConstructorOptionalCollectionBean.class);
SingleConstructorOptionalCollectionBean bean = (SingleConstructorOptionalCollectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getNestedTestBeans().size()).isEqualTo(2);
assertThat(bean.getNestedTestBeans().get(0)).isSameAs(ntb2);
@@ -1038,7 +984,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
SingleConstructorOptionalCollectionBean bean = bf.getBean("annotatedBean", SingleConstructorOptionalCollectionBean.class);
SingleConstructorOptionalCollectionBean bean = (SingleConstructorOptionalCollectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(tb);
assertThat(bean.getNestedTestBeans()).isNull();
}
@@ -1046,8 +992,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
@Test
public void testSingleConstructorInjectionWithMissingDependency() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SingleConstructorOptionalCollectionBean.class));
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
.isThrownBy(() -> bf.getBean("annotatedBean"));
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() ->
bf.getBean("annotatedBean"));
}
@Test
@@ -1056,8 +1002,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
RootBeanDefinition tb = new RootBeanDefinition(NullFactoryMethods.class);
tb.setFactoryMethodName("createTestBean");
bf.registerBeanDefinition("testBean", tb);
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
.isThrownBy(() -> bf.getBean("annotatedBean"));
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() ->
bf.getBean("annotatedBean"));
}
@Test
@@ -1066,7 +1012,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
ConstructorsResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsResourceInjectionBean.class);
ConstructorsResourceInjectionBean bean = (ConstructorsResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isSameAs(tb);
assertThat(bean.getTestBean4()).isNull();
}
@@ -1075,7 +1021,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public void testConstructorResourceInjectionWithMultipleCandidatesAndDefaultFallback() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ConstructorsResourceInjectionBean.class));
ConstructorsResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsResourceInjectionBean.class);
ConstructorsResourceInjectionBean bean = (ConstructorsResourceInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean3()).isNull();
assertThat(bean.getTestBean4()).isNull();
}
@@ -1091,12 +1037,12 @@ public class AutowiredAnnotationBeanPostProcessorTests {
tb2.setFactoryMethodName("createTestBean");
bf.registerBeanDefinition("testBean2", tb2);
MapConstructorInjectionBean bean = bf.getBean("annotatedBean", MapConstructorInjectionBean.class);
MapConstructorInjectionBean bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanMap().size()).isEqualTo(1);
assertThat(bean.getTestBeanMap().get("testBean1")).isSameAs(tb1);
assertThat(bean.getTestBeanMap().get("testBean2")).isNull();
bean = bf.getBean("annotatedBean", MapConstructorInjectionBean.class);
bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanMap().size()).isEqualTo(1);
assertThat(bean.getTestBeanMap().get("testBean1")).isSameAs(tb1);
assertThat(bean.getTestBeanMap().get("testBean2")).isNull();
@@ -1112,14 +1058,14 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerSingleton("testBean1", tb1);
bf.registerSingleton("testBean2", tb2);
MapFieldInjectionBean bean = bf.getBean("annotatedBean", MapFieldInjectionBean.class);
MapFieldInjectionBean bean = (MapFieldInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanMap().size()).isEqualTo(2);
assertThat(bean.getTestBeanMap().keySet().contains("testBean1")).isTrue();
assertThat(bean.getTestBeanMap().keySet().contains("testBean2")).isTrue();
assertThat(bean.getTestBeanMap().values().contains(tb1)).isTrue();
assertThat(bean.getTestBeanMap().values().contains(tb2)).isTrue();
bean = bf.getBean("annotatedBean", MapFieldInjectionBean.class);
bean = (MapFieldInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanMap().size()).isEqualTo(2);
assertThat(bean.getTestBeanMap().keySet().contains("testBean1")).isTrue();
assertThat(bean.getTestBeanMap().keySet().contains("testBean2")).isTrue();
@@ -1135,13 +1081,13 @@ public class AutowiredAnnotationBeanPostProcessorTests {
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
MapMethodInjectionBean bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
MapMethodInjectionBean bean = (MapMethodInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanMap().size()).isEqualTo(1);
assertThat(bean.getTestBeanMap().keySet().contains("testBean")).isTrue();
assertThat(bean.getTestBeanMap().values().contains(tb)).isTrue();
assertThat(bean.getTestBean()).isSameAs(tb);
bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
bean = (MapMethodInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanMap().size()).isEqualTo(1);
assertThat(bean.getTestBeanMap().keySet().contains("testBean")).isTrue();
assertThat(bean.getTestBeanMap().values().contains(tb)).isTrue();
@@ -1153,9 +1099,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class));
bf.registerBeanDefinition("testBean1", new RootBeanDefinition(TestBean.class));
bf.registerBeanDefinition("testBean2", new RootBeanDefinition(TestBean.class));
assertThatExceptionOfType(UnsatisfiedDependencyException.class).as("should have failed, more than one bean of type")
.isThrownBy(() -> bf.getBean("annotatedBean"))
.satisfies(methodParameterDeclaredOn(MapMethodInjectionBean.class));
assertThatExceptionOfType(UnsatisfiedDependencyException.class).as("should have failed, more than one bean of type").isThrownBy(() ->
bf.getBean("annotatedBean"))
.satisfies(methodParameterDeclaredOn(MapMethodInjectionBean.class));
}
@Test
@@ -1166,8 +1112,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
rbd2.setAutowireCandidate(false);
bf.registerBeanDefinition("testBean2", rbd2);
MapMethodInjectionBean bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
TestBean tb = bf.getBean("testBean1", TestBean.class);
MapMethodInjectionBean bean = (MapMethodInjectionBean) bf.getBean("annotatedBean");
TestBean tb = (TestBean) bf.getBean("testBean1");
assertThat(bean.getTestBeanMap().size()).isEqualTo(1);
assertThat(bean.getTestBeanMap().keySet().contains("testBean1")).isTrue();
assertThat(bean.getTestBeanMap().values().contains(tb)).isTrue();
@@ -1178,7 +1124,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public void testMethodInjectionWithMapAndNoMatches() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class));
MapMethodInjectionBean bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
MapMethodInjectionBean bean = (MapMethodInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanMap()).isNull();
assertThat(bean.getTestBean()).isNull();
}
@@ -1194,9 +1140,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerSingleton("testBeans", tbm);
bf.registerSingleton("otherMap", new Properties());
MapConstructorInjectionBean bean = bf.getBean("annotatedBean", MapConstructorInjectionBean.class);
MapConstructorInjectionBean bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanMap()).isSameAs(tbm);
bean = bf.getBean("annotatedBean", MapConstructorInjectionBean.class);
bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanMap()).isSameAs(tbm);
}
@@ -1210,9 +1156,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("myTestBeanMap", tbm);
bf.registerSingleton("otherMap", new HashMap<>());
MapConstructorInjectionBean bean = bf.getBean("annotatedBean", MapConstructorInjectionBean.class);
MapConstructorInjectionBean bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("myTestBeanMap"));
bean = bf.getBean("annotatedBean", MapConstructorInjectionBean.class);
bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("myTestBeanMap"));
}
@@ -1227,9 +1173,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerSingleton("testBean1", new TestBean());
bf.registerSingleton("testBean2", new TestBean());
CustomMapConstructorInjectionBean bean = bf.getBean("annotatedBean", CustomMapConstructorInjectionBean.class);
CustomMapConstructorInjectionBean bean = (CustomMapConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("myTestBeanMap"));
bean = bf.getBean("annotatedBean", CustomMapConstructorInjectionBean.class);
bean = (CustomMapConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("myTestBeanMap"));
}
@@ -1240,9 +1186,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("annotatedBean", bd);
bf.registerBeanDefinition("myTestBeanMap", new RootBeanDefinition(HashMap.class));
QualifiedMapConstructorInjectionBean bean = bf.getBean("annotatedBean", QualifiedMapConstructorInjectionBean.class);
QualifiedMapConstructorInjectionBean bean = (QualifiedMapConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("myTestBeanMap"));
bean = bf.getBean("annotatedBean", QualifiedMapConstructorInjectionBean.class);
bean = (QualifiedMapConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("myTestBeanMap"));
}
@@ -1257,9 +1203,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerSingleton("testBeans", tbs);
bf.registerSingleton("otherSet", new HashSet<>());
SetConstructorInjectionBean bean = bf.getBean("annotatedBean", SetConstructorInjectionBean.class);
SetConstructorInjectionBean bean = (SetConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanSet()).isSameAs(tbs);
bean = bf.getBean("annotatedBean", SetConstructorInjectionBean.class);
bean = (SetConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanSet()).isSameAs(tbs);
}
@@ -1273,9 +1219,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("myTestBeanSet", tbs);
bf.registerSingleton("otherSet", new HashSet<>());
SetConstructorInjectionBean bean = bf.getBean("annotatedBean", SetConstructorInjectionBean.class);
SetConstructorInjectionBean bean = (SetConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanSet()).isSameAs(bf.getBean("myTestBeanSet"));
bean = bf.getBean("annotatedBean", SetConstructorInjectionBean.class);
bean = (SetConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanSet()).isSameAs(bf.getBean("myTestBeanSet"));
}
@@ -1288,9 +1234,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
tbs.setUniqueFactoryMethodName("testBeanSet");
bf.registerBeanDefinition("myTestBeanSet", tbs);
CustomSetConstructorInjectionBean bean = bf.getBean("annotatedBean", CustomSetConstructorInjectionBean.class);
CustomSetConstructorInjectionBean bean = (CustomSetConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanSet()).isSameAs(bf.getBean("myTestBeanSet"));
bean = bf.getBean("annotatedBean", CustomSetConstructorInjectionBean.class);
bean = (CustomSetConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBeanSet()).isSameAs(bf.getBean("myTestBeanSet"));
}
@@ -1298,7 +1244,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public void testSelfReference() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionBean.class));
SelfInjectionBean bean = bf.getBean("annotatedBean", SelfInjectionBean.class);
SelfInjectionBean bean = (SelfInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.reference).isSameAs(bean);
assertThat(bean.referenceCollection).isNull();
}
@@ -1308,8 +1254,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionBean.class));
bf.registerBeanDefinition("annotatedBean2", new RootBeanDefinition(SelfInjectionBean.class));
SelfInjectionBean bean = bf.getBean("annotatedBean", SelfInjectionBean.class);
SelfInjectionBean bean2 = bf.getBean("annotatedBean2", SelfInjectionBean.class);
SelfInjectionBean bean = (SelfInjectionBean) bf.getBean("annotatedBean");
SelfInjectionBean bean2 = (SelfInjectionBean) bf.getBean("annotatedBean2");
assertThat(bean.reference).isSameAs(bean2);
assertThat(bean.referenceCollection.size()).isEqualTo(1);
assertThat(bean.referenceCollection.get(0)).isSameAs(bean2);
@@ -1319,7 +1265,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public void testSelfReferenceCollection() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionCollectionBean.class));
SelfInjectionCollectionBean bean = bf.getBean("annotatedBean", SelfInjectionCollectionBean.class);
SelfInjectionCollectionBean bean = (SelfInjectionCollectionBean) bf.getBean("annotatedBean");
assertThat(bean.reference).isSameAs(bean);
assertThat(bean.referenceCollection).isNull();
}
@@ -1329,8 +1275,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionCollectionBean.class));
bf.registerBeanDefinition("annotatedBean2", new RootBeanDefinition(SelfInjectionCollectionBean.class));
SelfInjectionCollectionBean bean = bf.getBean("annotatedBean", SelfInjectionCollectionBean.class);
SelfInjectionCollectionBean bean2 = bf.getBean("annotatedBean2", SelfInjectionCollectionBean.class);
SelfInjectionCollectionBean bean = (SelfInjectionCollectionBean) bf.getBean("annotatedBean");
SelfInjectionCollectionBean bean2 = (SelfInjectionCollectionBean) bf.getBean("annotatedBean2");
assertThat(bean.reference).isSameAs(bean2);
assertThat(bean2.referenceCollection.size()).isSameAs(1);
assertThat(bean.referenceCollection.get(0)).isSameAs(bean2);
@@ -1341,7 +1287,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
ObjectFactoryFieldInjectionBean bean = bf.getBean("annotatedBean", ObjectFactoryFieldInjectionBean.class);
ObjectFactoryFieldInjectionBean bean = (ObjectFactoryFieldInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
}
@@ -1350,7 +1296,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryConstructorInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
ObjectFactoryConstructorInjectionBean bean = bf.getBean("annotatedBean", ObjectFactoryConstructorInjectionBean.class);
ObjectFactoryConstructorInjectionBean bean = (ObjectFactoryConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
}
@@ -1361,9 +1307,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("annotatedBean", annotatedBeanDefinition);
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
ObjectFactoryFieldInjectionBean bean = bf.getBean("annotatedBean", ObjectFactoryFieldInjectionBean.class);
ObjectFactoryFieldInjectionBean bean = (ObjectFactoryFieldInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
ObjectFactoryFieldInjectionBean anotherBean = bf.getBean("annotatedBean", ObjectFactoryFieldInjectionBean.class);
ObjectFactoryFieldInjectionBean anotherBean = (ObjectFactoryFieldInjectionBean) bf.getBean("annotatedBean");
assertThat(bean).isNotSameAs(anotherBean);
assertThat(anotherBean.getTestBean()).isSameAs(bf.getBean("testBean"));
}
@@ -1376,7 +1322,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("dependencyBean", bd);
bf.registerBeanDefinition("dependencyBean2", new RootBeanDefinition(TestBean.class));
ObjectFactoryQualifierInjectionBean bean = bf.getBean("annotatedBean", ObjectFactoryQualifierInjectionBean.class);
ObjectFactoryQualifierInjectionBean bean = (ObjectFactoryQualifierInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(bf.getBean("dependencyBean"));
}
@@ -1388,7 +1334,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("dependencyBean", bd);
bf.registerBeanDefinition("dependencyBean2", new RootBeanDefinition(TestBean.class));
ObjectFactoryQualifierInjectionBean bean = bf.getBean("annotatedBean", ObjectFactoryQualifierInjectionBean.class);
ObjectFactoryQualifierInjectionBean bean = (ObjectFactoryQualifierInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(bf.getBean("dependencyBean"));
}
@@ -1398,7 +1344,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
ObjectFactoryFieldInjectionBean bean = bf.getBean("annotatedBean", ObjectFactoryFieldInjectionBean.class);
ObjectFactoryFieldInjectionBean bean = (ObjectFactoryFieldInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
bean = SerializationTestUtils.serializeAndDeserialize(bean);
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
@@ -1411,7 +1357,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
tbd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("testBean", tbd);
ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class);
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isEqualTo(bf.getBean("testBean"));
assertThat(bean.getTestBean("myName")).isEqualTo(bf.getBean("testBean", "myName"));
assertThat(bean.getOptionalTestBean()).isEqualTo(bf.getBean("testBean"));
@@ -1440,7 +1386,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectProviderInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class);
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
assertThat(bean.getOptionalTestBean()).isSameAs(bf.getBean("testBean"));
assertThat(bean.getOptionalTestBeanWithDefault()).isSameAs(bf.getBean("testBean"));
@@ -1467,7 +1413,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public void testObjectProviderInjectionWithTargetNotAvailable() {
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectProviderInjectionBean.class));
ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class);
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(
bean::getTestBean);
assertThat(bean.getOptionalTestBean()).isNull();
@@ -1493,7 +1439,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("testBean1", new RootBeanDefinition(TestBean.class));
bf.registerBeanDefinition("testBean2", new RootBeanDefinition(TestBean.class));
ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class);
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(bean::getTestBean);
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(bean::getOptionalTestBean);
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(bean::consumeOptionalTestBean);
@@ -1530,7 +1476,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
tb2.setLazyInit(true);
bf.registerBeanDefinition("testBean2", tb2);
ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class);
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean1"));
assertThat(bean.getOptionalTestBean()).isSameAs(bf.getBean("testBean1"));
assertThat(bean.consumeOptionalTestBean()).isSameAs(bf.getBean("testBean1"));
@@ -1568,7 +1514,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
tb2.setLazyInit(true);
bf.registerBeanDefinition("testBean2", tb2);
ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class);
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
List<?> testBeans = bean.sortedTestBeans();
assertThat(testBeans.size()).isEqualTo(2);
assertThat(testBeans.get(0)).isSameAs(bf.getBean("testBean2"));
@@ -1791,7 +1737,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
IntegerRepository ir = new IntegerRepository();
bf.registerSingleton("integerRepo", ir);
RepositoryFieldInjectionBean bean = bf.getBean("annotatedBean", RepositoryFieldInjectionBean.class);
RepositoryFieldInjectionBean bean = (RepositoryFieldInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.string).isSameAs(sv);
assertThat(bean.integer).isSameAs(iv);
assertThat(bean.stringArray.length).isSameAs(1);
@@ -1836,8 +1782,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
IntegerRepository ir = new IntegerRepository();
bf.registerSingleton("integerRepo", ir);
RepositoryFieldInjectionBeanWithSubstitutedVariables bean =
bf.getBean("annotatedBean", RepositoryFieldInjectionBeanWithSubstitutedVariables.class);
RepositoryFieldInjectionBeanWithSubstitutedVariables bean = (RepositoryFieldInjectionBeanWithSubstitutedVariables) bf.getBean("annotatedBean");
assertThat(bean.string).isSameAs(sv);
assertThat(bean.integer).isSameAs(iv);
assertThat(bean.stringArray.length).isSameAs(1);
@@ -1878,8 +1823,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
IntegerRepository ir = new IntegerRepository();
bf.registerSingleton("integerRepo", ir);
RepositoryFieldInjectionBeanWithQualifiers bean =
bf.getBean("annotatedBean", RepositoryFieldInjectionBeanWithQualifiers.class);
RepositoryFieldInjectionBeanWithQualifiers bean = (RepositoryFieldInjectionBeanWithQualifiers) bf.getBean("annotatedBean");
assertThat(bean.stringRepository).isSameAs(sr);
assertThat(bean.integerRepository).isSameAs(ir);
assertThat(bean.stringRepositoryArray.length).isSameAs(1);
@@ -1916,8 +1860,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
rbd.setQualifiedElement(ReflectionUtils.findField(getClass(), "integerRepositoryQualifierProvider"));
bf.registerBeanDefinition("integerRepository", rbd); // Bean name not matching qualifier
RepositoryFieldInjectionBeanWithQualifiers bean =
bf.getBean("annotatedBean", RepositoryFieldInjectionBeanWithQualifiers.class);
RepositoryFieldInjectionBeanWithQualifiers bean = (RepositoryFieldInjectionBeanWithQualifiers) bf.getBean("annotatedBean");
Repository<?> sr = bf.getBean("stringRepo", Repository.class);
Repository<?> ir = bf.getBean("integerRepository", Repository.class);
assertThat(bean.stringRepository).isSameAs(sr);
@@ -1944,8 +1887,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerSingleton("repo", new StringRepository());
RepositoryFieldInjectionBeanWithSimpleMatch bean =
bf.getBean("annotatedBean", RepositoryFieldInjectionBeanWithSimpleMatch.class);
RepositoryFieldInjectionBeanWithSimpleMatch bean = (RepositoryFieldInjectionBeanWithSimpleMatch) bf.getBean("annotatedBean");
Repository<?> repo = bf.getBean("repo", Repository.class);
assertThat(bean.repository).isSameAs(repo);
assertThat(bean.stringRepository).isSameAs(repo);
@@ -1972,7 +1914,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("annotatedBean", bd);
bf.registerBeanDefinition("repoFactoryBean", new RootBeanDefinition(RepositoryFactoryBean.class));
RepositoryFactoryBeanInjectionBean bean = bf.getBean("annotatedBean", RepositoryFactoryBeanInjectionBean.class);
RepositoryFactoryBeanInjectionBean bean = (RepositoryFactoryBeanInjectionBean) bf.getBean("annotatedBean");
RepositoryFactoryBean<?> repoFactoryBean = bf.getBean("&repoFactoryBean", RepositoryFactoryBean.class);
assertThat(bean.repositoryFactoryBean).isSameAs(repoFactoryBean);
}
@@ -1984,7 +1926,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.registerBeanDefinition("annotatedBean", bd);
bf.registerSingleton("repoFactoryBean", new RepositoryFactoryBean<>());
RepositoryFactoryBeanInjectionBean bean = bf.getBean("annotatedBean", RepositoryFactoryBeanInjectionBean.class);
RepositoryFactoryBeanInjectionBean bean = (RepositoryFactoryBeanInjectionBean) bf.getBean("annotatedBean");
RepositoryFactoryBean<?> repoFactoryBean = bf.getBean("&repoFactoryBean", RepositoryFactoryBean.class);
assertThat(bean.repositoryFactoryBean).isSameAs(repoFactoryBean);
}
@@ -2003,7 +1945,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
rbd.getConstructorArgumentValues().addGenericArgumentValue(Repository.class);
bf.registerBeanDefinition("repo", rbd);
RepositoryFieldInjectionBeanWithSimpleMatch bean = bf.getBean("annotatedBean", RepositoryFieldInjectionBeanWithSimpleMatch.class);
RepositoryFieldInjectionBeanWithSimpleMatch bean = (RepositoryFieldInjectionBeanWithSimpleMatch) bf.getBean("annotatedBean");
Repository<?> repo = bf.getBean("repo", Repository.class);
assertThat(bean.repository).isSameAs(repo);
assertThat(bean.stringRepository).isSameAs(repo);
@@ -2034,7 +1976,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
rbd.getConstructorArgumentValues().addGenericArgumentValue(new TypedStringValue(Repository.class.getName()));
bf.registerBeanDefinition("repo", rbd);
RepositoryFieldInjectionBeanWithSimpleMatch bean = bf.getBean("annotatedBean", RepositoryFieldInjectionBeanWithSimpleMatch.class);
RepositoryFieldInjectionBeanWithSimpleMatch bean = (RepositoryFieldInjectionBeanWithSimpleMatch) bf.getBean("annotatedBean");
Repository<?> repo = bf.getBean("repo", Repository.class);
assertThat(bean.repository).isSameAs(repo);
assertThat(bean.stringRepository).isSameAs(repo);
@@ -2066,7 +2008,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
IntegerRepository ir = new IntegerRepository();
bf.registerSingleton("integerRepo", ir);
RepositoryMethodInjectionBean bean = bf.getBean("annotatedBean", RepositoryMethodInjectionBean.class);
RepositoryMethodInjectionBean bean = (RepositoryMethodInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.string).isSameAs(sv);
assertThat(bean.integer).isSameAs(iv);
assertThat(bean.stringArray.length).isSameAs(1);
@@ -2111,8 +2053,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
IntegerRepository ir = new IntegerRepository();
bf.registerSingleton("integerRepo", ir);
RepositoryMethodInjectionBeanWithSubstitutedVariables bean =
bf.getBean("annotatedBean", RepositoryMethodInjectionBeanWithSubstitutedVariables.class);
RepositoryMethodInjectionBeanWithSubstitutedVariables bean = (RepositoryMethodInjectionBeanWithSubstitutedVariables) bf.getBean("annotatedBean");
assertThat(bean.string).isSameAs(sv);
assertThat(bean.integer).isSameAs(iv);
assertThat(bean.stringArray.length).isSameAs(1);
@@ -2153,7 +2094,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
IntegerRepository ir = new IntegerRepository();
bf.registerSingleton("integerRepo", ir);
RepositoryConstructorInjectionBean bean = bf.getBean("annotatedBean", RepositoryConstructorInjectionBean.class);
RepositoryConstructorInjectionBean bean = (RepositoryConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.stringRepository).isSameAs(sr);
assertThat(bean.integerRepository).isSameAs(ir);
assertThat(bean.stringRepositoryArray.length).isSameAs(1);
@@ -2179,7 +2120,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
GenericRepository gr = new GenericRepository();
bf.registerSingleton("genericRepo", gr);
RepositoryConstructorInjectionBean bean = bf.getBean("annotatedBean", RepositoryConstructorInjectionBean.class);
RepositoryConstructorInjectionBean bean = (RepositoryConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.stringRepository).isSameAs(gr);
assertThat(bean.integerRepository).isSameAs(gr);
assertThat(bean.stringRepositoryArray.length).isSameAs(1);
@@ -2204,7 +2145,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
SimpleRepository ngr = new SimpleRepository();
bf.registerSingleton("simpleRepo", ngr);
RepositoryConstructorInjectionBean bean = bf.getBean("annotatedBean", RepositoryConstructorInjectionBean.class);
RepositoryConstructorInjectionBean bean = (RepositoryConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.stringRepository).isSameAs(ngr);
assertThat(bean.integerRepository).isSameAs(ngr);
assertThat(bean.stringRepositoryArray.length).isSameAs(1);
@@ -2232,7 +2173,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
GenericRepository gr = new GenericRepositorySubclass();
bf.registerSingleton("genericRepo", gr);
RepositoryConstructorInjectionBean bean = bf.getBean("annotatedBean", RepositoryConstructorInjectionBean.class);
RepositoryConstructorInjectionBean bean = (RepositoryConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.stringRepository).isSameAs(sr);
assertThat(bean.integerRepository).isSameAs(gr);
assertThat(bean.stringRepositoryArray.length).isSameAs(1);
@@ -2259,7 +2200,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
SimpleRepository ngr = new SimpleRepositorySubclass();
bf.registerSingleton("simpleRepo", ngr);
RepositoryConstructorInjectionBean bean = bf.getBean("annotatedBean", RepositoryConstructorInjectionBean.class);
RepositoryConstructorInjectionBean bean = (RepositoryConstructorInjectionBean) bf.getBean("annotatedBean");
assertThat(bean.stringRepository).isSameAs(sr);
assertThat(bean.integerRepository).isSameAs(ngr);
assertThat(bean.stringRepositoryArray.length).isSameAs(1);
@@ -3955,20 +3896,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
}
public static class SometimesNullFactoryMethods {
public static boolean active = false;
public static TestBean createTestBean() {
return (active ? new TestBean() : null);
}
public static NestedTestBean createNestedTestBean() {
return (active ? new NestedTestBean() : null);
}
}
public static class ProvidedArgumentBean {
public ProvidedArgumentBean(String[] args) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2019 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.
@@ -28,32 +28,36 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Chris Beams
* @since 04.07.2006
*/
class DefaultSingletonBeanRegistryTests {
private final DefaultSingletonBeanRegistry beanRegistry = new DefaultSingletonBeanRegistry();
public class DefaultSingletonBeanRegistryTests {
@Test
void singletons() {
public void testSingletons() {
DefaultSingletonBeanRegistry beanRegistry = new DefaultSingletonBeanRegistry();
TestBean tb = new TestBean();
beanRegistry.registerSingleton("tb", tb);
assertThat(beanRegistry.getSingleton("tb")).isSameAs(tb);
TestBean tb2 = (TestBean) beanRegistry.getSingleton("tb2", TestBean::new);
TestBean tb2 = (TestBean) beanRegistry.getSingleton("tb2", () -> new TestBean());
assertThat(beanRegistry.getSingleton("tb2")).isSameAs(tb2);
assertThat(beanRegistry.getSingleton("tb")).isSameAs(tb);
assertThat(beanRegistry.getSingleton("tb2")).isSameAs(tb2);
assertThat(beanRegistry.getSingletonCount()).isEqualTo(2);
assertThat(beanRegistry.getSingletonNames()).containsExactly("tb", "tb2");
String[] names = beanRegistry.getSingletonNames();
assertThat(names.length).isEqualTo(2);
assertThat(names[0]).isEqualTo("tb");
assertThat(names[1]).isEqualTo("tb2");
beanRegistry.destroySingletons();
assertThat(beanRegistry.getSingletonCount()).isZero();
assertThat(beanRegistry.getSingletonNames()).isEmpty();
assertThat(beanRegistry.getSingletonCount()).isEqualTo(0);
assertThat(beanRegistry.getSingletonNames().length).isEqualTo(0);
}
@Test
void disposableBean() {
public void testDisposableBean() {
DefaultSingletonBeanRegistry beanRegistry = new DefaultSingletonBeanRegistry();
DerivedTestBean tb = new DerivedTestBean();
beanRegistry.registerSingleton("tb", tb);
beanRegistry.registerDisposableBean("tb", tb);
@@ -61,16 +65,21 @@ class DefaultSingletonBeanRegistryTests {
assertThat(beanRegistry.getSingleton("tb")).isSameAs(tb);
assertThat(beanRegistry.getSingletonCount()).isEqualTo(1);
assertThat(beanRegistry.getSingletonNames()).containsExactly("tb");
String[] names = beanRegistry.getSingletonNames();
assertThat(names.length).isEqualTo(1);
assertThat(names[0]).isEqualTo("tb");
assertThat(tb.wasDestroyed()).isFalse();
beanRegistry.destroySingletons();
assertThat(beanRegistry.getSingletonCount()).isZero();
assertThat(beanRegistry.getSingletonNames()).isEmpty();
assertThat(beanRegistry.getSingletonCount()).isEqualTo(0);
assertThat(beanRegistry.getSingletonNames().length).isEqualTo(0);
assertThat(tb.wasDestroyed()).isTrue();
}
@Test
void dependentRegistration() {
public void testDependentRegistration() {
DefaultSingletonBeanRegistry beanRegistry = new DefaultSingletonBeanRegistry();
beanRegistry.registerDependentBean("a", "b");
beanRegistry.registerDependentBean("b", "c");
beanRegistry.registerDependentBean("c", "b");
@@ -189,11 +189,13 @@ public class CaffeineCacheManager implements CacheManager {
@Override
@Nullable
public Cache getCache(String name) {
Cache cache = this.cacheMap.get(name);
if (cache == null && this.dynamic) {
cache = this.cacheMap.computeIfAbsent(name, this::createCaffeineCache);
if (this.dynamic) {
Cache cache = this.cacheMap.get(name);
return (cache != null) ? cache : this.cacheMap.computeIfAbsent(name, this::createCaffeineCache);
}
else {
return this.cacheMap.get(name);
}
return cache;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 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.
@@ -166,7 +166,13 @@ public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderA
public Cache getCache(String name) {
Cache cache = this.cacheMap.get(name);
if (cache == null && this.dynamic) {
cache = this.cacheMap.computeIfAbsent(name, this::createConcurrentMapCache);
synchronized (this.cacheMap) {
cache = this.cacheMap.get(name);
if (cache == null) {
cache = createConcurrentMapCache(name);
this.cacheMap.put(name, cache);
}
}
}
return cache;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -21,8 +21,8 @@ import org.springframework.instrument.classloading.LoadTimeWeaver;
/**
* Interface to be implemented by
* {@link org.springframework.context.annotation.Configuration @Configuration}
* classes annotated with {@link EnableLoadTimeWeaving @EnableLoadTimeWeaving}
* that wish to customize the {@link LoadTimeWeaver} instance to be used.
* classes annotated with {@link EnableLoadTimeWeaving @EnableLoadTimeWeaving} that wish to
* customize the {@link LoadTimeWeaver} instance to be used.
*
* <p>See {@link org.springframework.scheduling.annotation.EnableAsync @EnableAsync}
* for usage examples and information on how a default {@code LoadTimeWeaver}
@@ -36,9 +36,9 @@ import org.springframework.instrument.classloading.LoadTimeWeaver;
public interface LoadTimeWeavingConfigurer {
/**
* Create, configure and return the {@code LoadTimeWeaver} instance to be used.
* Note that it is unnecessary to annotate this method with {@code @Bean}
* because the object returned will automatically be registered as a bean by
* Create, configure and return the {@code LoadTimeWeaver} instance to be used. Note
* that it is unnecessary to annotate this method with {@code @Bean}, because the
* object returned will automatically be registered as a bean by
* {@link LoadTimeWeavingConfiguration#loadTimeWeaver()}
*/
LoadTimeWeaver getLoadTimeWeaver();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -367,7 +367,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
* Return the target bean instance to use.
*/
protected Object getTargetBean() {
Assert.notNull(this.applicationContext, "ApplicationContext must not be null");
Assert.notNull(this.applicationContext, "ApplicationContext must no be null");
return this.applicationContext.getBean(this.beanName);
}
@@ -749,8 +749,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null &&
beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -21,8 +21,6 @@ import java.security.ProtectionDomain;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.DecoratingClassLoader;
import org.springframework.core.OverridingClassLoader;
import org.springframework.core.SmartClassLoader;
@@ -47,26 +45,15 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart
}
@Nullable
private static final Method findLoadedClassMethod;
private static Method findLoadedClassMethod;
static {
// Try to enable findLoadedClass optimization which allows us to selectively
// override classes that have not been loaded yet. If not accessible, we will
// always override requested classes, even when the classes have been loaded
// by the parent ClassLoader already and cannot be transformed anymore anyway.
Method method = null;
try {
method = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
ReflectionUtils.makeAccessible(method);
findLoadedClassMethod = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
}
catch (Throwable ex) {
// Typically a JDK 9+ InaccessibleObjectException...
// Avoid through JVM startup with --add-opens=java.base/java.lang=ALL-UNNAMED
LogFactory.getLog(ContextTypeMatchClassLoader.class).debug(
"ClassLoader.findLoadedClass not accessible -> will always override requested class", ex);
catch (NoSuchMethodException ex) {
throw new IllegalStateException("Invalid [java.lang.ClassLoader] class: no 'findLoadedClass' method defined!");
}
findLoadedClassMethod = method;
}
@@ -109,14 +96,13 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart
if (isExcluded(className) || ContextTypeMatchClassLoader.this.isExcluded(className)) {
return false;
}
if (findLoadedClassMethod != null) {
ClassLoader parent = getParent();
while (parent != null) {
if (ReflectionUtils.invokeMethod(findLoadedClassMethod, parent, className) != null) {
return false;
}
parent = parent.getParent();
ReflectionUtils.makeAccessible(findLoadedClassMethod);
ClassLoader parent = getParent();
while (parent != null) {
if (ReflectionUtils.invokeMethod(findLoadedClassMethod, parent, className) != null) {
return false;
}
parent = parent.getParent();
}
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 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.
@@ -64,10 +64,9 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
/**
* Specify the maximum time allotted in milliseconds for the shutdown of any
* phase (group of {@link SmartLifecycle} beans with the same 'phase' value).
* <p>The default value is 30000 milliseconds (30 seconds).
* @see SmartLifecycle#getPhase()
* Specify the maximum time allotted in milliseconds for the shutdown of
* any phase (group of SmartLifecycle beans with the same 'phase' value).
* <p>The default value is 30 seconds.
*/
public void setTimeoutPerShutdownPhase(long timeoutPerShutdownPhase) {
this.timeoutPerShutdownPhase = timeoutPerShutdownPhase;
@@ -206,9 +206,9 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
@Override
public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
long delay = startTime.getTime() - this.clock.millis();
long initialDelay = startTime.getTime() - this.clock.millis();
try {
return this.scheduledExecutor.schedule(decorateTask(task, false), delay, TimeUnit.MILLISECONDS);
return this.scheduledExecutor.schedule(decorateTask(task, false), initialDelay, TimeUnit.MILLISECONDS);
}
catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
@@ -108,9 +108,9 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
/**
* Set whether to wait for scheduled tasks to complete on shutdown,
* not interrupting running tasks and executing all tasks in the queue.
* <p>Default is {@code false}, shutting down immediately through interrupting
* ongoing tasks and clearing the queue. Switch this flag to {@code true} if
* you prefer fully completed tasks at the expense of a longer shutdown phase.
* <p>Default is "false", shutting down immediately through interrupting
* ongoing tasks and clearing the queue. Switch this flag to "true" if you
* prefer fully completed tasks at the expense of a longer shutdown phase.
* <p>Note that Spring's container shutdown continues while ongoing tasks
* are being completed. If you want this executor to block and wait for the
* termination of tasks before the rest of the container continues to shut
@@ -211,13 +211,9 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
}
/**
* Perform a full shutdown on the underlying ExecutorService,
* according to the corresponding configuration settings.
* @see #setWaitForTasksToCompleteOnShutdown
* @see #setAwaitTerminationMillis
* Perform a shutdown on the underlying ExecutorService.
* @see java.util.concurrent.ExecutorService#shutdown()
* @see java.util.concurrent.ExecutorService#shutdownNow()
* @see java.util.concurrent.ExecutorService#awaitTermination
*/
public void shutdown() {
if (logger.isDebugEnabled()) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 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.
@@ -78,8 +78,8 @@ class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements Sc
if (this.scheduledExecutionTime == null) {
return null;
}
long delay = this.scheduledExecutionTime.getTime() - this.triggerContext.getClock().millis();
this.currentFuture = this.executor.schedule(this, delay, TimeUnit.MILLISECONDS);
long initialDelay = this.scheduledExecutionTime.getTime() - this.triggerContext.getClock().millis();
this.currentFuture = this.executor.schedule(this, initialDelay, TimeUnit.MILLISECONDS);
return this;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 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.
@@ -380,9 +380,9 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
@Override
public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
ScheduledExecutorService executor = getScheduledExecutor();
long delay = startTime.getTime() - this.clock.millis();
long initialDelay = startTime.getTime() - this.clock.millis();
try {
return executor.schedule(errorHandlingTask(task, false), delay, TimeUnit.MILLISECONDS);
return executor.schedule(errorHandlingTask(task, false), initialDelay, TimeUnit.MILLISECONDS);
}
catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
@@ -124,10 +124,8 @@ public class FieldError extends ObjectError {
@Override
public String toString() {
// We would preferably use ObjectUtils.nullSafeConciseToString(rejectedValue) here but
// keep including the full nullSafeToString representation for backwards compatibility.
return "Field error in object '" + getObjectName() + "' on field '" + this.field +
"': rejected value [" + ObjectUtils.nullSafeToString(this.rejectedValue) + "]; " +
"': rejected value [" + ObjectUtils.nullSafeConciseToString(this.rejectedValue) + "]; " +
resolvableToString();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -108,7 +108,7 @@ open class BeanDefinitionDsl internal constructor (private val init: BeanDefinit
SINGLETON,
/**
* Scope constant for the standard prototype scope
* Scope constant for the standard singleton scope
* @see org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE
*/
PROTOTYPE
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 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.
@@ -207,9 +207,10 @@ public class ClassPathBeanDefinitionScannerTests {
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.setIncludeAnnotationConfig(false);
scanner.scan("org.springframework.context.annotation3");
assertThatIllegalStateException().isThrownBy(() -> scanner.scan(BASE_PACKAGE))
.withMessageContaining("stubFooDao")
.withMessageContaining(StubFooDao.class.getName());
assertThatIllegalStateException().isThrownBy(() ->
scanner.scan(BASE_PACKAGE))
.withMessageContaining("stubFooDao")
.withMessageContaining(StubFooDao.class.getName());
}
@Test
@@ -266,10 +267,11 @@ public class ClassPathBeanDefinitionScannerTests {
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.setIncludeAnnotationConfig(false);
scanner.scan("org.springframework.context.annotation2");
assertThatIllegalStateException().isThrownBy(() -> scanner.scan(BASE_PACKAGE))
.withMessageContaining("myNamedDao")
.withMessageContaining(NamedStubDao.class.getName())
.withMessageContaining(NamedStubDao2.class.getName());
assertThatIllegalStateException().isThrownBy(() ->
scanner.scan(BASE_PACKAGE))
.withMessageContaining("myNamedDao")
.withMessageContaining(NamedStubDao.class.getName())
.withMessageContaining(NamedStubDao2.class.getName());
}
@Test
@@ -79,7 +79,7 @@ class EnableLoadTimeWeavingTests {
@Configuration
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.DISABLED)
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.DISABLED)
static class EnableLTWConfig_withAjWeavingDisabled implements LoadTimeWeavingConfigurer {
@Override
@@ -88,9 +88,8 @@ class EnableLoadTimeWeavingTests {
}
}
@Configuration
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.AUTODETECT)
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.AUTODETECT)
static class EnableLTWConfig_withAjWeavingAutodetect implements LoadTimeWeavingConfigurer {
@Override
@@ -99,9 +98,8 @@ class EnableLoadTimeWeavingTests {
}
}
@Configuration
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.ENABLED)
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
static class EnableLTWConfig_withAjWeavingEnabled implements LoadTimeWeavingConfigurer {
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 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,7 +19,6 @@ package org.springframework.context.event;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.List;
import org.junit.jupiter.api.Test;
@@ -47,8 +46,6 @@ import static org.mockito.Mockito.verify;
/**
* @author Stephane Nicoll
* @author Juergen Hoeller
* @author Simon Baslé
*/
public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEventListenerTests {
@@ -83,23 +80,16 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv
supportsEventType(false, method, ResolvableType.forClassWithGenerics(GenericTestEvent.class, Long.class));
}
@Test
public void genericListenerWithUnresolvedGenerics() {
Method method = ReflectionUtils.findMethod(
SampleEvents.class, "handleGenericString", GenericTestEvent.class);
supportsEventType(true, method, ResolvableType.forClass(GenericTestEvent.class));
}
@Test
public void listenerWithPayloadAndGenericInformation() {
Method method = ReflectionUtils.findMethod(SampleEvents.class, "handleString", String.class);
supportsEventType(true, method, createPayloadEventType(String.class));
supportsEventType(true, method, createGenericEventType(String.class));
}
@Test
public void listenerWithInvalidPayloadAndGenericInformation() {
Method method = ReflectionUtils.findMethod(SampleEvents.class, "handleString", String.class);
supportsEventType(false, method, createPayloadEventType(Integer.class));
supportsEventType(false, method, createGenericEventType(Integer.class));
}
@Test
@@ -123,28 +113,28 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv
@Test
public void listenerWithAnnotationValue() {
Method method = ReflectionUtils.findMethod(SampleEvents.class, "handleStringAnnotationValue");
supportsEventType(true, method, createPayloadEventType(String.class));
supportsEventType(true, method, createGenericEventType(String.class));
}
@Test
public void listenerWithAnnotationClasses() {
Method method = ReflectionUtils.findMethod(SampleEvents.class, "handleStringAnnotationClasses");
supportsEventType(true, method, createPayloadEventType(String.class));
supportsEventType(true, method, createGenericEventType(String.class));
}
@Test
public void listenerWithAnnotationValueAndParameter() {
Method method = ReflectionUtils.findMethod(
SampleEvents.class, "handleStringAnnotationValueAndParameter", String.class);
supportsEventType(true, method, createPayloadEventType(String.class));
supportsEventType(true, method, createGenericEventType(String.class));
}
@Test
public void listenerWithSeveralTypes() {
Method method = ReflectionUtils.findMethod(SampleEvents.class, "handleStringOrInteger");
supportsEventType(true, method, createPayloadEventType(String.class));
supportsEventType(true, method, createPayloadEventType(Integer.class));
supportsEventType(false, method, createPayloadEventType(Double.class));
supportsEventType(true, method, createGenericEventType(String.class));
supportsEventType(true, method, createGenericEventType(Integer.class));
supportsEventType(false, method, createGenericEventType(Double.class));
}
@Test
@@ -335,88 +325,6 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv
verify(this.context, times(2)).getBean("testBean");
}
@Test // gh-30399
void simplePayloadDoesNotSupportArbitraryGenericEventType() throws Exception {
Method method = SampleEvents.class.getDeclaredMethod("handleString", String.class);
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClassWithGenerics(EntityWrapper.class, Integer.class))))
.as("handleString(String) with EntityWrapper<Integer>").isFalse();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClass(EntityWrapper.class))))
.as("handleString(String) with EntityWrapper<?>").isFalse();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClass(String.class))))
.as("handleString(String) with String").isTrue();
}
@Test // gh-30399
void genericPayloadDoesNotSupportArbitraryGenericEventType() throws Exception {
Method method = SampleEvents.class.getDeclaredMethod("handleGenericStringPayload", EntityWrapper.class);
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClass(EntityWrapper.class))))
.as("handleGenericStringPayload(EntityWrapper<String>) with EntityWrapper<?>").isFalse();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClassWithGenerics(EntityWrapper.class, Integer.class))))
.as("handleGenericStringPayload(EntityWrapper<String>) with EntityWrapper<Integer>").isFalse();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClassWithGenerics(EntityWrapper.class, String.class))))
.as("handleGenericStringPayload(EntityWrapper<String>) with EntityWrapper<String>").isTrue();
}
@Test // gh-30399
void rawGenericPayloadDoesNotSupportArbitraryGenericEventType() throws Exception {
Method method = SampleEvents.class.getDeclaredMethod("handleGenericAnyPayload", EntityWrapper.class);
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClass(EntityWrapper.class))))
.as("handleGenericAnyPayload(EntityWrapper<?>) with EntityWrapper<?>").isTrue();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClassWithGenerics(EntityWrapper.class, Integer.class))))
.as("handleGenericAnyPayload(EntityWrapper<?>) with EntityWrapper<Integer>").isTrue();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClassWithGenerics(EntityWrapper.class, String.class))))
.as("handleGenericAnyPayload(EntityWrapper<?>) with EntityWrapper<String>").isTrue();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClass(List.class))))
.as("handleGenericAnyPayload(EntityWrapper<?>) with List<?>").isFalse();
assertThat(adapter.supportsEventType(createPayloadEventType(ResolvableType.forClassWithGenerics(List.class, String.class))))
.as("handleGenericAnyPayload(EntityWrapper<?>) with List<String>").isFalse();
}
@Test // gh-30399
void genericApplicationEventSupportsSpecificType() throws Exception {
Method method = SampleEvents.class.getDeclaredMethod("handleGenericString", GenericTestEvent.class);
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
assertThat(adapter.supportsEventType(ResolvableType.forClass(GenericTestEvent.class)))
.as("handleGenericString(GenericTestEvent<String>) with GenericTestEvent<?>").isTrue();
assertThat(adapter.supportsEventType(ResolvableType.forClassWithGenerics(GenericTestEvent.class, Integer.class)))
.as("handleGenericString(GenericTestEvent<String>) with GenericTestEvent<Integer>").isFalse();
assertThat(adapter.supportsEventType(ResolvableType.forClassWithGenerics(GenericTestEvent.class, String.class)))
.as("handleGenericString(GenericTestEvent<String>) with GenericTestEvent<String>").isTrue();
}
@Test // gh-30399
void genericRawApplicationEventSupportsRawTypeAndAnySpecificType() throws Exception {
Method method = SampleEvents.class.getDeclaredMethod("handleGenericRaw", GenericTestEvent.class);
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
assertThat(adapter.supportsEventType(ResolvableType.forClass(GenericTestEvent.class)))
.as("handleGenericRaw(GenericTestEvent<?>) with GenericTestEvent<?>").isTrue();
assertThat(adapter.supportsEventType(ResolvableType.forClassWithGenerics(GenericTestEvent.class, String.class)))
.as("handleGenericRaw(GenericTestEvent<?>) with GenericTestEvent<String>").isTrue();
assertThat(adapter.supportsEventType(ResolvableType.forClassWithGenerics(GenericTestEvent.class, Integer.class)))
.as("handleGenericRaw(GenericTestEvent<?>) with GenericTestEvent<Integer>").isTrue();
}
@Test // gh-30399
void unrelatedApplicationEventDoesNotSupportRawTypeOrAnySpecificType() throws Exception {
Method method = SampleEvents.class.getDeclaredMethod("handleUnrelated", ContextRefreshedEvent.class);
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
assertThat(adapter.supportsEventType(ResolvableType.forClass(GenericTestEvent.class)))
.as("handleUnrelated(ContextRefreshedEvent) with GenericTestEvent<?>").isTrue(); // known bug in 5.3.x
assertThat(adapter.supportsEventType(ResolvableType.forClassWithGenerics(GenericTestEvent.class, String.class)))
.as("handleUnrelated(ContextRefreshedEvent) with GenericTestEvent<String>").isFalse();
assertThat(adapter.supportsEventType(ResolvableType.forClassWithGenerics(GenericTestEvent.class, Integer.class)))
.as("handleUnrelated(ContextRefreshedEvent) with GenericTestEvent<Integer>").isFalse();
}
private void supportsEventType(boolean match, Method method, ResolvableType eventType) {
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
@@ -433,11 +341,7 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv
return new StaticApplicationListenerMethodAdapter(method, this.sampleEvents);
}
private ResolvableType createPayloadEventType(Class<?> payloadType) {
return ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, payloadType);
}
private ResolvableType createPayloadEventType(ResolvableType payloadType) {
private ResolvableType createGenericEventType(Class<?> payloadType) {
return ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, payloadType);
}
@@ -469,14 +373,6 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv
public void handleGenericString(GenericTestEvent<String> event) {
}
@EventListener
public void handleGenericRaw(GenericTestEvent<?> event) {
}
@EventListener
public void handleUnrelated(ContextRefreshedEvent event) {
}
@EventListener
public void handleString(String payload) {
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2019 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.
@@ -85,13 +85,16 @@ public class ReflectiveLoadTimeWeaverTests {
private int numTimesAddTransformerCalled = 0;
public int getNumTimesGetThrowawayClassLoaderCalled() {
return this.numTimesAddTransformerCalled;
}
public void addTransformer(ClassFileTransformer transformer) {
++this.numTimesAddTransformerCalled;
}
}
@@ -99,15 +102,18 @@ public class ReflectiveLoadTimeWeaverTests {
private int numTimesGetThrowawayClassLoaderCalled = 0;
@Override
public int getNumTimesGetThrowawayClassLoaderCalled() {
return this.numTimesGetThrowawayClassLoaderCalled;
}
public ClassLoader getThrowawayClassLoader() {
++this.numTimesGetThrowawayClassLoaderCalled;
return getClass().getClassLoader();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2019 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.
@@ -95,8 +95,9 @@ public class EnableAsyncTests {
public void properExceptionForExistingProxyDependencyMismatch() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AsyncConfig.class, AsyncBeanWithInterface.class, AsyncBeanUser.class);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(ctx::refresh)
.withCauseInstanceOf(BeanNotOfRequiredTypeException.class);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
ctx::refresh)
.withCauseInstanceOf(BeanNotOfRequiredTypeException.class);
ctx.close();
}
@@ -104,8 +105,9 @@ public class EnableAsyncTests {
public void properExceptionForResolvedProxyDependencyMismatch() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AsyncConfig.class, AsyncBeanUser.class, AsyncBeanWithInterface.class);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(ctx::refresh)
.withCauseInstanceOf(BeanNotOfRequiredTypeException.class);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
ctx::refresh)
.withCauseInstanceOf(BeanNotOfRequiredTypeException.class);
ctx.close();
}
@@ -180,7 +182,8 @@ public class EnableAsyncTests {
@SuppressWarnings("resource")
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AspectJAsyncAnnotationConfig.class);
assertThatExceptionOfType(BeanDefinitionStoreException.class).isThrownBy(ctx::refresh);
assertThatExceptionOfType(BeanDefinitionStoreException.class).isThrownBy(
ctx::refresh);
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 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.
@@ -61,7 +61,7 @@ public class EnableSchedulingTests {
@EnabledForTestGroups(LONG_RUNNING)
public void withFixedRateTask() throws InterruptedException {
ctx = new AnnotationConfigApplicationContext(FixedRateTaskConfig.class);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(2);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks().size()).isEqualTo(2);
Thread.sleep(100);
assertThat(ctx.getBean(AtomicInteger.class).get()).isGreaterThanOrEqualTo(10);
@@ -71,7 +71,7 @@ public class EnableSchedulingTests {
@EnabledForTestGroups(LONG_RUNNING)
public void withSubclass() throws InterruptedException {
ctx = new AnnotationConfigApplicationContext(FixedRateTaskConfigSubclass.class);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(2);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks().size()).isEqualTo(2);
Thread.sleep(100);
assertThat(ctx.getBean(AtomicInteger.class).get()).isGreaterThanOrEqualTo(10);
@@ -81,13 +81,13 @@ public class EnableSchedulingTests {
@EnabledForTestGroups(LONG_RUNNING)
public void withExplicitScheduler() throws InterruptedException {
ctx = new AnnotationConfigApplicationContext(ExplicitSchedulerConfig.class);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(1);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks().size()).isEqualTo(1);
Thread.sleep(100);
assertThat(ctx.getBean(AtomicInteger.class).get()).isGreaterThanOrEqualTo(10);
assertThat(ctx.getBean(ExplicitSchedulerConfig.class).threadName).startsWith("explicitScheduler-");
assertThat(Arrays.asList(ctx.getDefaultListableBeanFactory().getDependentBeans("myTaskScheduler")).contains(
TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)).isTrue();
TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)).isTrue();
}
@Test
@@ -100,7 +100,7 @@ public class EnableSchedulingTests {
@EnabledForTestGroups(LONG_RUNNING)
public void withExplicitScheduledTaskRegistrar() throws InterruptedException {
ctx = new AnnotationConfigApplicationContext(ExplicitScheduledTaskRegistrarConfig.class);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(1);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks().size()).isEqualTo(1);
Thread.sleep(100);
assertThat(ctx.getBean(AtomicInteger.class).get()).isGreaterThanOrEqualTo(10);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 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.
@@ -55,7 +55,7 @@ abstract class AbstractSchedulingTaskExecutorTests {
@BeforeEach
void setup(TestInfo testInfo) {
void setUp(TestInfo testInfo) {
this.testName = testInfo.getTestMethod().get().getName();
this.threadNamePrefix = this.testName + "-";
this.executor = buildExecutor();
@@ -84,11 +84,11 @@ abstract class AbstractSchedulingTaskExecutorTests {
TestTask task = new TestTask(this.testName, 0);
executor.execute(task);
Awaitility.await()
.dontCatchUncaughtExceptions()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> task.exception.get() != null && task.exception.get().getMessage().equals(
"TestTask failure for test 'executeFailingRunnable': expectedRunCount:<0>, actualRunCount:<1>"));
.dontCatchUncaughtExceptions()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> task.exception.get() != null && task.exception.get().getMessage().equals(
"TestTask failure for test 'executeFailingRunnable': expectedRunCount:<0>, actualRunCount:<1>"));
}
@Test
@@ -101,7 +101,7 @@ abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
void submitFailingRunnable() {
void submitFailingRunnable() throws Exception {
TestTask task = new TestTask(this.testName, 0);
Future<?> future = executor.submit(task);
assertThatExceptionOfType(ExecutionException.class).isThrownBy(() ->
@@ -121,31 +121,31 @@ abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
void submitListenableRunnable() {
void submitListenableRunnable() throws Exception {
TestTask task = new TestTask(this.testName, 1);
// Act
ListenableFuture<?> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
// Assert
Awaitility.await()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(future::isDone);
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(future::isDone);
assertThat(outcome).isNull();
assertThreadNamePrefix(task);
}
@Test
void submitFailingListenableRunnable() {
void submitFailingListenableRunnable() throws Exception {
TestTask task = new TestTask(this.testName, 0);
ListenableFuture<?> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
Awaitility.await()
.dontCatchUncaughtExceptions()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> future.isDone() && outcome != null);
.dontCatchUncaughtExceptions()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> future.isDone() && outcome != null);
assertThat(outcome.getClass()).isSameAs(RuntimeException.class);
}
@@ -159,13 +159,14 @@ abstract class AbstractSchedulingTaskExecutorTests {
future1.get(1000, TimeUnit.MILLISECONDS);
}
catch (Exception ex) {
// ignore
/* ignore */
}
Awaitility.await()
.atMost(4, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.untilAsserted(() -> assertThatExceptionOfType(CancellationException.class)
.isThrownBy(() -> future2.get(1000, TimeUnit.MILLISECONDS)));
.atMost(4, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.untilAsserted(() ->
assertThatExceptionOfType(CancellationException.class).isThrownBy(() ->
future2.get(1000, TimeUnit.MILLISECONDS)));
}
@Test
@@ -177,11 +178,11 @@ abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
void submitFailingCallable() {
void submitFailingCallable() throws Exception {
TestCallable task = new TestCallable(this.testName, 0);
Future<String> future = executor.submit(task);
assertThatExceptionOfType(ExecutionException.class)
.isThrownBy(() -> future.get(1000, TimeUnit.MILLISECONDS));
assertThatExceptionOfType(ExecutionException.class).isThrownBy(() ->
future.get(1000, TimeUnit.MILLISECONDS));
assertThat(future.isDone()).isTrue();
}
@@ -195,41 +196,42 @@ abstract class AbstractSchedulingTaskExecutorTests {
future1.get(1000, TimeUnit.MILLISECONDS);
}
catch (Exception ex) {
// ignore
/* ignore */
}
Awaitility.await()
.atMost(4, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.untilAsserted(() -> assertThatExceptionOfType(CancellationException.class)
.isThrownBy(() -> future2.get(1000, TimeUnit.MILLISECONDS)));
.atMost(4, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.untilAsserted(() ->
assertThatExceptionOfType(CancellationException.class).isThrownBy(() ->
future2.get(1000, TimeUnit.MILLISECONDS)));
}
@Test
void submitListenableCallable() {
void submitListenableCallable() throws Exception {
TestCallable task = new TestCallable(this.testName, 1);
// Act
ListenableFuture<String> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
// Assert
Awaitility.await()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> future.isDone() && outcome != null);
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> future.isDone() && outcome != null);
assertThat(outcome.toString().substring(0, this.threadNamePrefix.length())).isEqualTo(this.threadNamePrefix);
}
@Test
void submitFailingListenableCallable() {
void submitFailingListenableCallable() throws Exception {
TestCallable task = new TestCallable(this.testName, 0);
// Act
ListenableFuture<String> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
// Assert
Awaitility.await()
.dontCatchUncaughtExceptions()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> future.isDone() && outcome != null);
.dontCatchUncaughtExceptions()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> future.isDone() && outcome != null);
assertThat(outcome.getClass()).isSameAs(RuntimeException.class);
}
@@ -294,9 +296,8 @@ abstract class AbstractSchedulingTaskExecutorTests {
}
if (expectedRunCount >= 0) {
if (actualRunCount.incrementAndGet() > expectedRunCount) {
RuntimeException exception = new RuntimeException(String.format(
"%s failure for test '%s': expectedRunCount:<%d>, actualRunCount:<%d>",
getClass().getSimpleName(), this.testName, expectedRunCount, actualRunCount.get()));
RuntimeException exception = new RuntimeException(String.format("%s failure for test '%s': expectedRunCount:<%d>, actualRunCount:<%d>",
getClass().getSimpleName(), this.testName, expectedRunCount, actualRunCount.get()));
this.exception.set(exception);
throw exception;
}
@@ -328,9 +329,8 @@ abstract class AbstractSchedulingTaskExecutorTests {
}
if (expectedRunCount >= 0) {
if (actualRunCount.incrementAndGet() > expectedRunCount) {
throw new RuntimeException(String.format(
"%s failure for test '%s': expectedRunCount:<%d>, actualRunCount:<%d>",
getClass().getSimpleName(), this.testName, expectedRunCount, actualRunCount.get()));
throw new RuntimeException(String.format("%s failure for test '%s': expectedRunCount:<%d>, actualRunCount:<%d>",
getClass().getSimpleName(), this.testName, expectedRunCount, actualRunCount.get()));
}
}
return Thread.currentThread().getName();
@@ -89,24 +89,19 @@ class ConcurrentTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
private static class DecoratedRunnable implements Runnable {
@Override
public void run() {
}
}
private static class RunnableDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
return new DecoratedRunnable();
}
}
private static class DecoratedExecutor implements Executor {
@Override
public void execute(Runnable command) {
Assert.state(command instanceof DecoratedRunnable, "TaskDecorator not applied");
@@ -41,14 +41,14 @@ import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
class ScheduledExecutorFactoryBeanTests {
@Test
void throwsExceptionIfPoolSizeIsLessThanZero() {
void throwsExceptionIfPoolSizeIsLessThanZero() throws Exception {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
assertThatIllegalArgumentException().isThrownBy(() -> factory.setPoolSize(-1));
}
@Test
@SuppressWarnings("serial")
void shutdownNowIsPropagatedToTheExecutorOnDestroy() {
void shutdownNowIsPropagatedToTheExecutorOnDestroy() throws Exception {
final ScheduledExecutorService executor = mock(ScheduledExecutorService.class);
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
@@ -66,7 +66,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@SuppressWarnings("serial")
void shutdownIsPropagatedToTheExecutorOnDestroy() {
void shutdownIsPropagatedToTheExecutorOnDestroy() throws Exception {
final ScheduledExecutorService executor = mock(ScheduledExecutorService.class);
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
@@ -85,7 +85,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@EnabledForTestGroups(LONG_RUNNING)
void oneTimeExecutionIsSetUpAndFiresCorrectly() {
void oneTimeExecutionIsSetUpAndFiresCorrectly() throws Exception {
Runnable runnable = mock(Runnable.class);
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
@@ -99,7 +99,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@EnabledForTestGroups(LONG_RUNNING)
void fixedRepeatedExecutionIsSetUpAndFiresCorrectly() {
void fixedRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception {
Runnable runnable = mock(Runnable.class);
ScheduledExecutorTask task = new ScheduledExecutorTask(runnable);
@@ -117,7 +117,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@EnabledForTestGroups(LONG_RUNNING)
void fixedRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() {
void fixedRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception {
Runnable runnable = mock(Runnable.class);
willThrow(new IllegalStateException()).given(runnable).run();
@@ -137,7 +137,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@EnabledForTestGroups(LONG_RUNNING)
void withInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectly() {
void withInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception {
Runnable runnable = mock(Runnable.class);
ScheduledExecutorTask task = new ScheduledExecutorTask(runnable);
@@ -157,7 +157,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@EnabledForTestGroups(LONG_RUNNING)
void withInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() {
void withInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception {
Runnable runnable = mock(Runnable.class);
willThrow(new IllegalStateException()).given(runnable).run();
@@ -179,7 +179,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@SuppressWarnings("serial")
void settingThreadFactoryToNullForcesUseOfDefaultButIsOtherwiseCool() {
void settingThreadFactoryToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
@Override
protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
@@ -195,7 +195,7 @@ class ScheduledExecutorFactoryBeanTests {
@Test
@SuppressWarnings("serial")
void settingRejectedExecutionHandlerToNullForcesUseOfDefaultButIsOtherwiseCool() {
void settingRejectedExecutionHandlerToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
@Override
protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
@@ -210,7 +210,7 @@ class ScheduledExecutorFactoryBeanTests {
}
@Test
void objectTypeReportsCorrectType() {
void objectTypeReportsCorrectType() throws Exception {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
assertThat(factory.getObjectType()).isEqualTo(ScheduledExecutorService.class);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 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,8 +26,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.InstanceOfAssertFactories.type;
/**
@@ -67,7 +67,8 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
assertThat(executor.getCorePoolSize()).isEqualTo(1);
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isEqualTo(1);
assertThatIllegalArgumentException().isThrownBy(() -> executor.setCorePoolSize(-1));
assertThatThrownBy(() -> executor.setCorePoolSize(-1))
.isInstanceOf(IllegalArgumentException.class);
assertThat(executor.getCorePoolSize()).isEqualTo(1);
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isEqualTo(1);
@@ -89,7 +90,8 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
assertThat(executor.getMaxPoolSize()).isEqualTo(1);
assertThat(executor.getThreadPoolExecutor().getMaximumPoolSize()).isEqualTo(1);
assertThatIllegalArgumentException().isThrownBy(() -> executor.setMaxPoolSize(0));
assertThatThrownBy(() -> executor.setMaxPoolSize(0))
.isInstanceOf(IllegalArgumentException.class);
assertThat(executor.getMaxPoolSize()).isEqualTo(1);
assertThat(executor.getThreadPoolExecutor().getMaximumPoolSize()).isEqualTo(1);
@@ -111,7 +113,8 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
assertThat(executor.getKeepAliveSeconds()).isEqualTo(60);
assertThat(executor.getThreadPoolExecutor().getKeepAliveTime(TimeUnit.SECONDS)).isEqualTo(60);
assertThatIllegalArgumentException().isThrownBy(() -> executor.setKeepAliveSeconds(-10));
assertThatThrownBy(() -> executor.setKeepAliveSeconds(-10))
.isInstanceOf(IllegalArgumentException.class);
assertThat(executor.getKeepAliveSeconds()).isEqualTo(60);
assertThat(executor.getThreadPoolExecutor().getKeepAliveTime(TimeUnit.SECONDS)).isEqualTo(60);
@@ -121,8 +124,8 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
void queueCapacityDefault() {
assertThat(executor.getQueueCapacity()).isEqualTo(Integer.MAX_VALUE);
assertThat(executor.getThreadPoolExecutor().getQueue())
.asInstanceOf(type(LinkedBlockingQueue.class))
.extracting(BlockingQueue::remainingCapacity).isEqualTo(Integer.MAX_VALUE);
.asInstanceOf(type(LinkedBlockingQueue.class))
.extracting(BlockingQueue::remainingCapacity).isEqualTo(Integer.MAX_VALUE);
}
@Test
@@ -132,8 +135,8 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
assertThat(executor.getQueueCapacity()).isZero();
assertThat(executor.getThreadPoolExecutor().getQueue())
.asInstanceOf(type(SynchronousQueue.class))
.extracting(BlockingQueue::remainingCapacity).isEqualTo(0);
.asInstanceOf(type(SynchronousQueue.class))
.extracting(BlockingQueue::remainingCapacity).isEqualTo(0);
}
@Test
@@ -576,17 +576,15 @@ public class ReflectUtils {
c = (Class) lookupDefineClassMethod.invoke(lookup, b);
}
catch (InvocationTargetException ex) {
Throwable target = ex.getTargetException();
if (target.getClass() != LinkageError.class && target.getClass() != IllegalAccessException.class) {
throw new CodeGenerationException(target);
}
throw new CodeGenerationException(target) {
throw new CodeGenerationException(ex.getTargetException());
}
catch (IllegalAccessException ex) {
throw new CodeGenerationException(ex) {
@Override
public String getMessage() {
return "ClassLoader mismatch for [" + contextClass.getName() +
"]: JVM should be started with --add-opens=java.base/java.lang=ALL-UNNAMED " +
"for ClassLoader.defineClass to be accessible on " + loader.getClass().getName() +
"; consider co-locating the affected class in that target ClassLoader instead.";
"for ClassLoader.defineClass to be accessible on " + loader.getClass().getName();
}
};
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 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.
@@ -133,9 +133,6 @@ public class ResolvableType implements Serializable {
@Nullable
private volatile ResolvableType[] generics;
@Nullable
private volatile Boolean unresolvableGenerics;
/**
* Private constructor used to create a new {@link ResolvableType} for cache key purposes,
@@ -548,15 +545,6 @@ public class ResolvableType implements Serializable {
if (this == NONE) {
return false;
}
Boolean unresolvableGenerics = this.unresolvableGenerics;
if (unresolvableGenerics == null) {
unresolvableGenerics = determineUnresolvableGenerics();
this.unresolvableGenerics = unresolvableGenerics;
}
return unresolvableGenerics;
}
private boolean determineUnresolvableGenerics() {
ResolvableType[] generics = getGenerics();
for (ResolvableType generic : generics) {
if (generic.isUnresolvableTypeVariable() || generic.isWildcardWithoutBounds()) {
@@ -568,7 +556,7 @@ public class ResolvableType implements Serializable {
try {
for (Type genericInterface : resolved.getGenericInterfaces()) {
if (genericInterface instanceof Class) {
if (((Class<?>) genericInterface).getTypeParameters().length > 0) {
if (forClass((Class<?>) genericInterface).hasGenerics()) {
return true;
}
}
@@ -577,10 +565,7 @@ public class ResolvableType implements Serializable {
catch (TypeNotPresentException ex) {
// Ignore non-present types in generic signature
}
Class<?> superclass = resolved.getSuperclass();
if (superclass != null && superclass != Object.class) {
return getSuperType().hasUnresolvableGenerics();
}
return getSuperType().hasUnresolvableGenerics();
}
return false;
}
@@ -22,6 +22,7 @@ import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
@@ -203,18 +204,19 @@ final class SerializableTypeWrapper {
return forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, -1));
}
else if (Type[].class == method.getReturnType() && ObjectUtils.isEmpty(args)) {
Object returnValue = ReflectionUtils.invokeMethod(method, this.provider.getType());
if (returnValue == null) {
return null;
}
Type[] result = new Type[((Type[]) returnValue).length];
Type[] result = new Type[((Type[]) method.invoke(this.provider.getType())).length];
for (int i = 0; i < result.length; i++) {
result[i] = forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, i));
}
return result;
}
return ReflectionUtils.invokeMethod(method, this.provider.getType(), args);
try {
return method.invoke(this.provider.getType(), args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 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.
@@ -149,8 +149,8 @@ public abstract class AnnotationUtils {
* @since 5.2
* @see #isCandidateClass(Class, String)
*/
public static boolean isCandidateClass(Class<?> clazz, @Nullable Class<? extends Annotation> annotationType) {
return (annotationType != null && isCandidateClass(clazz, annotationType.getName()));
public static boolean isCandidateClass(Class<?> clazz, Class<? extends Annotation> annotationType) {
return isCandidateClass(clazz, annotationType.getName());
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2018 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.
@@ -96,25 +96,6 @@ public interface Environment extends PropertyResolver {
*/
String[] getDefaultProfiles();
/**
* Determine whether one of the given profile expressions matches the
* {@linkplain #getActiveProfiles() active profiles} &mdash; or in the case
* of no explicit active profiles, whether one of the given profile expressions
* matches the {@linkplain #getDefaultProfiles() default profiles}.
* <p>Profile expressions allow for complex, boolean profile logic to be
* expressed &mdash; for example {@code "p1 & p2"}, {@code "(p1 & p2) | p3"},
* etc. See {@link Profiles#of(String...)} for details on the supported
* expression syntax.
* <p>This method is a convenient shortcut for
* {@code env.acceptsProfiles(Profiles.of(profileExpressions))}.
* @since 5.3.28
* @see Profiles#of(String...)
* @see #acceptsProfiles(Profiles)
*/
default boolean matchesProfiles(String... profileExpressions) {
return acceptsProfiles(Profiles.of(profileExpressions));
}
/**
* Determine whether one or more of the given profiles is active &mdash; or
* in the case of no explicit {@linkplain #getActiveProfiles() active profiles},
@@ -137,6 +118,25 @@ public interface Environment extends PropertyResolver {
@Deprecated
boolean acceptsProfiles(String... profiles);
/**
* Determine whether one of the given profile expressions matches the
* {@linkplain #getActiveProfiles() active profiles} &mdash; or in the case
* of no explicit active profiles, whether one of the given profile expressions
* matches the {@linkplain #getDefaultProfiles() default profiles}.
* <p>Profile expressions allow for complex, boolean profile logic to be
* expressed &mdash; for example {@code "p1 & p2"}, {@code "(p1 & p2) | p3"},
* etc. See {@link Profiles#of(String...)} for details on the supported
* expression syntax.
* <p>This method is a convenient shortcut for
* {@code env.acceptsProfiles(Profiles.of(profileExpressions))}.
* @since 5.3.28
* @see Profiles#of(String...)
* @see #acceptsProfiles(Profiles)
*/
default boolean matchesProfiles(String... profileExpressions) {
return acceptsProfiles(Profiles.of(profileExpressions));
}
/**
* Determine whether the given {@link Profiles} predicate matches the
* {@linkplain #getActiveProfiles() active profiles} &mdash; or in the case
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -33,15 +33,13 @@ import org.springframework.util.StringUtils;
*
* <p>Supports resolution as {@code java.io.File} if the class path
* resource resides in the file system, but not for resources in a JAR.
* Always supports resolution as {@code java.net.URL}.
* Always supports resolution as URL.
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 28.12.2003
* @see ClassLoader#getResourceAsStream(String)
* @see ClassLoader#getResource(String)
* @see Class#getResourceAsStream(String)
* @see Class#getResource(String)
*/
public class ClassPathResource extends AbstractFileResolvingResource {
@@ -126,7 +124,7 @@ public class ClassPathResource extends AbstractFileResolvingResource {
}
/**
* Return the {@link ClassLoader} that this resource will be obtained from.
* Return the ClassLoader that this resource will be obtained from.
*/
@Nullable
public final ClassLoader getClassLoader() {
@@ -136,8 +134,8 @@ public class ClassPathResource extends AbstractFileResolvingResource {
/**
* This implementation checks for the resolution of a resource URL.
* @see ClassLoader#getResource(String)
* @see Class#getResource(String)
* @see java.lang.ClassLoader#getResource(String)
* @see java.lang.Class#getResource(String)
*/
@Override
public boolean exists() {
@@ -147,8 +145,8 @@ public class ClassPathResource extends AbstractFileResolvingResource {
/**
* This implementation checks for the resolution of a resource URL upfront,
* then proceeding with {@link AbstractFileResolvingResource}'s length check.
* @see ClassLoader#getResource(String)
* @see Class#getResource(String)
* @see java.lang.ClassLoader#getResource(String)
* @see java.lang.Class#getResource(String)
*/
@Override
public boolean isReadable() {
@@ -181,11 +179,9 @@ public class ClassPathResource extends AbstractFileResolvingResource {
}
/**
* This implementation opens an {@link InputStream} for the underlying class
* path resource, if available.
* @see ClassLoader#getResourceAsStream(String)
* @see Class#getResourceAsStream(String)
* @see ClassLoader#getSystemResourceAsStream(String)
* This implementation opens an InputStream for the given class path resource.
* @see java.lang.ClassLoader#getResourceAsStream(String)
* @see java.lang.Class#getResourceAsStream(String)
*/
@Override
public InputStream getInputStream() throws IOException {
@@ -208,8 +204,8 @@ public class ClassPathResource extends AbstractFileResolvingResource {
/**
* This implementation returns a URL for the underlying class path resource,
* if available.
* @see ClassLoader#getResource(String)
* @see Class#getResource(String)
* @see java.lang.ClassLoader#getResource(String)
* @see java.lang.Class#getResource(String)
*/
@Override
public URL getURL() throws IOException {
@@ -221,9 +217,9 @@ public class ClassPathResource extends AbstractFileResolvingResource {
}
/**
* This implementation creates a {@code ClassPathResource}, applying the given
* path relative to the path used to create this descriptor.
* @see StringUtils#applyRelativePath(String, String)
* This implementation creates a ClassPathResource, applying the given path
* relative to the path of the underlying resource of this descriptor.
* @see org.springframework.util.StringUtils#applyRelativePath(String, String)
*/
@Override
public Resource createRelative(String relativePath) {
@@ -235,7 +231,7 @@ public class ClassPathResource extends AbstractFileResolvingResource {
/**
* This implementation returns the name of the file that this class path
* resource refers to.
* @see StringUtils#getFilename(String)
* @see org.springframework.util.StringUtils#getFilename(String)
*/
@Override
@Nullable
@@ -281,7 +277,8 @@ public class ClassPathResource extends AbstractFileResolvingResource {
}
/**
* This implementation returns the hash code of the underlying class path location.
* This implementation returns the hash code of the underlying
* class path location.
*/
@Override
public int hashCode() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2019 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.
@@ -158,7 +158,6 @@ public class FileSystemResource extends AbstractResource implements WritableReso
/**
* This implementation returns whether the underlying file exists.
* @see java.io.File#exists()
* @see java.nio.file.Files#exists(Path, java.nio.file.LinkOption...)
*/
@Override
public boolean exists() {
@@ -170,8 +169,6 @@ public class FileSystemResource extends AbstractResource implements WritableReso
* (and corresponds to an actual file with content, not to a directory).
* @see java.io.File#canRead()
* @see java.io.File#isDirectory()
* @see java.nio.file.Files#isReadable(Path)
* @see java.nio.file.Files#isDirectory(Path, java.nio.file.LinkOption...)
*/
@Override
public boolean isReadable() {
@@ -180,8 +177,8 @@ public class FileSystemResource extends AbstractResource implements WritableReso
}
/**
* This implementation opens an NIO file stream for the underlying file.
* @see java.nio.file.Files#newInputStream(Path, java.nio.file.OpenOption...)
* This implementation opens a NIO file stream for the underlying file.
* @see java.io.FileInputStream
*/
@Override
public InputStream getInputStream() throws IOException {
@@ -198,8 +195,6 @@ public class FileSystemResource extends AbstractResource implements WritableReso
* (and corresponds to an actual file with content, not to a directory).
* @see java.io.File#canWrite()
* @see java.io.File#isDirectory()
* @see java.nio.file.Files#isWritable(Path)
* @see java.nio.file.Files#isDirectory(Path, java.nio.file.LinkOption...)
*/
@Override
public boolean isWritable() {
@@ -209,7 +204,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
/**
* This implementation opens a FileOutputStream for the underlying file.
* @see java.nio.file.Files#newOutputStream(Path, java.nio.file.OpenOption...)
* @see java.io.FileOutputStream
*/
@Override
public OutputStream getOutputStream() throws IOException {
@@ -219,7 +214,6 @@ public class FileSystemResource extends AbstractResource implements WritableReso
/**
* This implementation returns a URL for the underlying file.
* @see java.io.File#toURI()
* @see java.nio.file.Path#toUri()
*/
@Override
public URL getURL() throws IOException {
@@ -229,7 +223,6 @@ public class FileSystemResource extends AbstractResource implements WritableReso
/**
* This implementation returns a URI for the underlying file.
* @see java.io.File#toURI()
* @see java.nio.file.Path#toUri()
*/
@Override
public URI getURI() throws IOException {
@@ -331,7 +324,6 @@ public class FileSystemResource extends AbstractResource implements WritableReso
/**
* This implementation returns the name of the file.
* @see java.io.File#getName()
* @see java.nio.file.Path#getFileName()
*/
@Override
public String getFilename() {
@@ -342,7 +334,6 @@ public class FileSystemResource extends AbstractResource implements WritableReso
* This implementation returns a description that includes the absolute
* path of the file.
* @see java.io.File#getAbsolutePath()
* @see java.nio.file.Path#toAbsolutePath()
*/
@Override
public String getDescription() {
@@ -351,7 +342,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
/**
* This implementation compares the underlying file paths.
* This implementation compares the underlying File references.
*/
@Override
public boolean equals(@Nullable Object other) {
@@ -360,7 +351,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
}
/**
* This implementation returns the hash code of the underlying file path.
* This implementation returns the hash code of the underlying File reference.
*/
@Override
public int hashCode() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2019 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.
@@ -61,7 +61,7 @@ public class PathResource extends AbstractResource implements WritableResource {
/**
* Create a new {@code PathResource} from a {@link Path} handle.
* Create a new PathResource from a Path handle.
* <p>Note: Unlike {@link FileSystemResource}, when building relative resources
* via {@link #createRelative}, the relative path will be built <i>underneath</i>
* the given root: e.g. Paths.get("C:/dir1/"), relative path "dir2" &rarr; "C:/dir1/dir2"!
@@ -73,7 +73,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* Create a new {@code PathResource} from a path string.
* Create a new PathResource from a Path handle.
* <p>Note: Unlike {@link FileSystemResource}, when building relative resources
* via {@link #createRelative}, the relative path will be built <i>underneath</i>
* the given root: e.g. Paths.get("C:/dir1/"), relative path "dir2" &rarr; "C:/dir1/dir2"!
@@ -86,7 +86,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* Create a new {@code PathResource} from a {@link URI}.
* Create a new PathResource from a Path handle.
* <p>Note: Unlike {@link FileSystemResource}, when building relative resources
* via {@link #createRelative}, the relative path will be built <i>underneath</i>
* the given root: e.g. Paths.get("C:/dir1/"), relative path "dir2" &rarr; "C:/dir1/dir2"!
@@ -127,7 +127,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation opens an {@link InputStream} for the underlying file.
* This implementation opens a InputStream for the underlying file.
* @see java.nio.file.spi.FileSystemProvider#newInputStream(Path, OpenOption...)
*/
@Override
@@ -153,7 +153,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation opens an {@link OutputStream} for the underlying file.
* This implementation opens a OutputStream for the underlying file.
* @see java.nio.file.spi.FileSystemProvider#newOutputStream(Path, OpenOption...)
*/
@Override
@@ -165,7 +165,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation returns a {@link URL} for the underlying file.
* This implementation returns a URL for the underlying file.
* @see java.nio.file.Path#toUri()
* @see java.net.URI#toURL()
*/
@@ -175,7 +175,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation returns a {@link URI} for the underlying file.
* This implementation returns a URI for the underlying file.
* @see java.nio.file.Path#toUri()
*/
@Override
@@ -192,7 +192,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation returns the underlying {@link File} reference.
* This implementation returns the underlying File reference.
*/
@Override
public File getFile() throws IOException {
@@ -207,7 +207,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation opens a {@link ReadableByteChannel} for the underlying file.
* This implementation opens a Channel for the underlying file.
* @see Files#newByteChannel(Path, OpenOption...)
*/
@Override
@@ -221,7 +221,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation opens a {@link WritableByteChannel} for the underlying file.
* This implementation opens a Channel for the underlying file.
* @see Files#newByteChannel(Path, OpenOption...)
*/
@Override
@@ -238,7 +238,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation returns the underlying file's timestamp.
* This implementation returns the underlying File's timestamp.
* @see java.nio.file.Files#getLastModifiedTime(Path, java.nio.file.LinkOption...)
*/
@Override
@@ -249,7 +249,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation creates a {@link PathResource}, applying the given path
* This implementation creates a PathResource, applying the given path
* relative to the path of the underlying file of this resource descriptor.
* @see java.nio.file.Path#resolve(String)
*/
@@ -274,7 +274,7 @@ public class PathResource extends AbstractResource implements WritableResource {
/**
* This implementation compares the underlying {@link Path} references.
* This implementation compares the underlying Path references.
*/
@Override
public boolean equals(@Nullable Object other) {
@@ -283,7 +283,7 @@ public class PathResource extends AbstractResource implements WritableResource {
}
/**
* This implementation returns the hash code of the underlying {@link Path} reference.
* This implementation returns the hash code of the underlying Path reference.
*/
@Override
public int hashCode() {
@@ -16,26 +16,18 @@
package org.springframework.util;
import java.io.File;
import java.lang.reflect.Array;
import java.net.InetAddress;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.time.ZoneId;
import java.time.temporal.Temporal;
import java.util.Arrays;
import java.util.Collection;
import java.util.Currency;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.TimeZone;
import java.util.UUID;
import java.util.regex.Pattern;
import org.springframework.lang.Nullable;
@@ -69,9 +61,6 @@ public abstract class ObjectUtils {
private static final String EMPTY_ARRAY = ARRAY_START + ARRAY_END;
private static final String ARRAY_ELEMENT_SEPARATOR = ", ";
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
private static final String NON_EMPTY_ARRAY = ARRAY_START + "..." + ARRAY_END;
private static final String EMPTY_COLLECTION = "[]";
private static final String NON_EMPTY_COLLECTION = "[...]";
/**
@@ -934,31 +923,19 @@ public abstract class ObjectUtils {
* <p>Returns:
* <ul>
* <li>{@code "null"} if {@code obj} is {@code null}</li>
* <li>{@code"Optional.empty"} if {@code obj} is an empty {@link Optional}</li>
* <li>{@code"Optional[<concise-string>]"} if {@code obj} is a non-empty {@code Optional},
* where {@code <concise-string>} is the result of invoking {@link #nullSafeConciseToString}
* on the object contained in the {@code Optional}</li>
* <li>{@code "{}"} if {@code obj} is an empty array or {@link Map}</li>
* <li>{@code "{...}"} if {@code obj} is a non-empty array or {@link Map}</li>
* <li>{@code "[]"} if {@code obj} is an empty {@link Collection}</li>
* <li>{@code "[...]"} if {@code obj} is a non-empty {@link Collection}</li>
* <li>{@linkplain Class#getName() Class name} if {@code obj} is a {@link Class}</li>
* <li>{@linkplain Charset#name() Charset name} if {@code obj} is a {@link Charset}</li>
* <li>{@linkplain TimeZone#getID() TimeZone ID} if {@code obj} is a {@link TimeZone}</li>
* <li>{@linkplain ZoneId#getId() Zone ID} if {@code obj} is a {@link ZoneId}</li>
* <li>Potentially {@linkplain StringUtils#truncate(CharSequence) truncated string}
* if {@code obj} is a {@link String} or {@link CharSequence}</li>
* <li>Potentially {@linkplain StringUtils#truncate(CharSequence) truncated string}
* if {@code obj} is a <em>simple value type</em> whose {@code toString()} method
* returns a non-null value</li>
* returns a non-null value.</li>
* <li>Otherwise, a string representation of the object's type name concatenated
* with {@code "@"} and a hex string form of the object's identity hash code</li>
* with {@code @} and a hex string form of the object's identity hash code</li>
* </ul>
* <p>In the context of this method, a <em>simple value type</em> is any of the following:
* primitive wrapper (excluding {@link Void}), {@link Enum}, {@link Number},
* {@link Date}, {@link Temporal}, {@link File}, {@link Path}, {@link URI},
* {@link URL}, {@link InetAddress}, {@link Currency}, {@link Locale},
* {@link UUID}, {@link Pattern}.
* a primitive wrapper (excluding {@code Void}), an {@code Enum}, a {@code Number},
* a {@code Date}, a {@code Temporal}, a {@code UUID}, a {@code URI}, a {@code URL},
* or a {@code Locale}.
* @param obj the object to build a string representation for
* @return a concise string representation of the supplied object
* @since 5.3.27
@@ -969,33 +946,9 @@ public abstract class ObjectUtils {
if (obj == null) {
return "null";
}
if (obj instanceof Optional<?>) {
Optional<?> optional = (Optional<?>) obj;
return (!optional.isPresent() ? "Optional.empty" :
String.format("Optional[%s]", nullSafeConciseToString(optional.get())));
}
if (obj.getClass().isArray()) {
return (Array.getLength(obj) == 0 ? EMPTY_ARRAY : NON_EMPTY_ARRAY);
}
if (obj instanceof Collection<?>) {
return (((Collection<?>) obj).isEmpty() ? EMPTY_COLLECTION : NON_EMPTY_COLLECTION);
}
if (obj instanceof Map<?, ?>) {
// EMPTY_ARRAY and NON_EMPTY_ARRAY are also used for maps.
return (((Map<?, ?>) obj).isEmpty() ? EMPTY_ARRAY : NON_EMPTY_ARRAY);
}
if (obj instanceof Class<?>) {
return ((Class<?>) obj).getName();
}
if (obj instanceof Charset) {
return ((Charset) obj).name();
}
if (obj instanceof TimeZone) {
return ((TimeZone) obj).getID();
}
if (obj instanceof ZoneId) {
return ((ZoneId) obj).getId();
}
if (obj instanceof CharSequence) {
return StringUtils.truncate((CharSequence) obj);
}
@@ -1011,10 +964,7 @@ public abstract class ObjectUtils {
/**
* Derived from {@link org.springframework.beans.BeanUtils#isSimpleValueType}.
* <p>As of 5.3.28, considering {@link UUID} in addition to the bean-level check.
* <p>As of 5.3.29, additionally considering {@link File}, {@link Path},
* {@link InetAddress}, {@link Charset}, {@link Currency}, {@link TimeZone},
* {@link ZoneId}, {@link Pattern}.
* As of 5.3.28, considering {@code UUID} in addition to the bean-level check.
*/
private static boolean isSimpleValueType(Class<?> type) {
return (Void.class != type && void.class != type &&
@@ -1024,18 +974,10 @@ public abstract class ObjectUtils {
Number.class.isAssignableFrom(type) ||
Date.class.isAssignableFrom(type) ||
Temporal.class.isAssignableFrom(type) ||
ZoneId.class.isAssignableFrom(type) ||
TimeZone.class.isAssignableFrom(type) ||
File.class.isAssignableFrom(type) ||
Path.class.isAssignableFrom(type) ||
Charset.class.isAssignableFrom(type) ||
Currency.class.isAssignableFrom(type) ||
InetAddress.class.isAssignableFrom(type) ||
UUID.class == type ||
URI.class == type ||
URL.class == type ||
UUID.class == type ||
Locale.class == type ||
Pattern.class == type ||
Class.class == type));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -509,8 +509,16 @@ public abstract class ReflectionUtils {
* @see java.lang.Object#equals(Object)
*/
public static boolean isEqualsMethod(@Nullable Method method) {
return (method != null && method.getParameterCount() == 1 && method.getName().equals("equals") &&
method.getParameterTypes()[0] == Object.class);
if (method == null) {
return false;
}
if (method.getParameterCount() != 1) {
return false;
}
if (!method.getName().equals("equals")) {
return false;
}
return method.getParameterTypes()[0] == Object.class;
}
/**
@@ -518,7 +526,7 @@ public abstract class ReflectionUtils {
* @see java.lang.Object#hashCode()
*/
public static boolean isHashCodeMethod(@Nullable Method method) {
return (method != null && method.getParameterCount() == 0 && method.getName().equals("hashCode"));
return method != null && method.getParameterCount() == 0 && method.getName().equals("hashCode");
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 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.
@@ -342,31 +342,20 @@ class DefaultConversionServiceTests {
@Test
void convertArrayToCollectionInterface() {
@SuppressWarnings("unchecked")
Collection<String> result = conversionService.convert(new String[] {"1", "2", "3"}, Collection.class);
assertThat(result).isExactlyInstanceOf(LinkedHashSet.class).containsExactly("1", "2", "3");
}
@Test
void convertArrayToSetInterface() {
@SuppressWarnings("unchecked")
Collection<String> result = conversionService.convert(new String[] {"1", "2", "3"}, Set.class);
assertThat(result).isExactlyInstanceOf(LinkedHashSet.class).containsExactly("1", "2", "3");
}
@Test
void convertArrayToListInterface() {
@SuppressWarnings("unchecked")
List<String> result = conversionService.convert(new String[] {"1", "2", "3"}, List.class);
assertThat(result).isExactlyInstanceOf(ArrayList.class).containsExactly("1", "2", "3");
List<?> result = conversionService.convert(new String[] {"1", "2", "3"}, List.class);
assertThat(result.get(0)).isEqualTo("1");
assertThat(result.get(1)).isEqualTo("2");
assertThat(result.get(2)).isEqualTo("3");
}
@Test
void convertArrayToCollectionGenericTypeConversion() throws Exception {
@SuppressWarnings("unchecked")
List<Integer> result = (List<Integer>) conversionService.convert(new String[] {"1", "2", "3"},
TypeDescriptor.valueOf(String[].class), new TypeDescriptor(getClass().getDeclaredField("genericList")));
assertThat(result).isExactlyInstanceOf(ArrayList.class).containsExactly(1, 2, 3);
List<Integer> result = (List<Integer>) conversionService.convert(new String[] {"1", "2", "3"}, TypeDescriptor
.valueOf(String[].class), new TypeDescriptor(getClass().getDeclaredField("genericList")));
assertThat((int) result.get(0)).isEqualTo((int) Integer.valueOf(1));
assertThat((int) result.get(1)).isEqualTo((int) Integer.valueOf(2));
assertThat((int) result.get(2)).isEqualTo((int) Integer.valueOf(3));
}
@Test
@@ -394,9 +383,10 @@ class DefaultConversionServiceTests {
@Test
void convertArrayToCollectionImpl() {
@SuppressWarnings("unchecked")
ArrayList<String> result = conversionService.convert(new String[] {"1", "2", "3"}, ArrayList.class);
assertThat(result).isExactlyInstanceOf(ArrayList.class).containsExactly("1", "2", "3");
ArrayList<?> result = conversionService.convert(new String[] {"1", "2", "3"}, ArrayList.class);
assertThat(result.get(0)).isEqualTo("1");
assertThat(result.get(1)).isEqualTo("2");
assertThat(result.get(2)).isEqualTo("3");
}
@Test
@@ -426,25 +416,34 @@ class DefaultConversionServiceTests {
@Test
void convertStringToArray() {
String[] result = conversionService.convert("1,2,3", String[].class);
assertThat(result).containsExactly("1", "2", "3");
assertThat(result.length).isEqualTo(3);
assertThat(result[0]).isEqualTo("1");
assertThat(result[1]).isEqualTo("2");
assertThat(result[2]).isEqualTo("3");
}
@Test
void convertStringToArrayWithElementConversion() {
Integer[] result = conversionService.convert("1,2,3", Integer[].class);
assertThat(result).containsExactly(1, 2, 3);
assertThat(result.length).isEqualTo(3);
assertThat((int) result[0]).isEqualTo((int) Integer.valueOf(1));
assertThat((int) result[1]).isEqualTo((int) Integer.valueOf(2));
assertThat((int) result[2]).isEqualTo((int) Integer.valueOf(3));
}
@Test
void convertStringToPrimitiveArrayWithElementConversion() {
int[] result = conversionService.convert("1,2,3", int[].class);
assertThat(result).containsExactly(1, 2, 3);
assertThat(result.length).isEqualTo(3);
assertThat(result[0]).isEqualTo(1);
assertThat(result[1]).isEqualTo(2);
assertThat(result[2]).isEqualTo(3);
}
@Test
void convertEmptyStringToArray() {
String[] result = conversionService.convert("", String[].class);
assertThat(result).isEmpty();
assertThat(result.length).isEqualTo(0);
}
@Test
@@ -458,7 +457,7 @@ class DefaultConversionServiceTests {
void convertArrayToObjectWithElementConversion() {
String[] array = new String[] {"3"};
Integer result = conversionService.convert(array, Integer.class);
assertThat(result).isEqualTo(3);
assertThat((int) result).isEqualTo((int) Integer.valueOf(3));
}
@Test
@@ -471,27 +470,39 @@ class DefaultConversionServiceTests {
@Test
void convertObjectToArray() {
Object[] result = conversionService.convert(3L, Object[].class);
assertThat(result).containsExactly(3L);
assertThat(result.length).isEqualTo(1);
assertThat(result[0]).isEqualTo(3L);
}
@Test
void convertObjectToArrayWithElementConversion() {
Integer[] result = conversionService.convert(3L, Integer[].class);
assertThat(result).containsExactly(3);
assertThat(result.length).isEqualTo(1);
assertThat((int) result[0]).isEqualTo((int) Integer.valueOf(3));
}
@Test
void convertCollectionToArray() {
List<String> list = Arrays.asList("1", "2", "3");
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
String[] result = conversionService.convert(list, String[].class);
assertThat(result).containsExactly("1", "2", "3");
assertThat(result[0]).isEqualTo("1");
assertThat(result[1]).isEqualTo("2");
assertThat(result[2]).isEqualTo("3");
}
@Test
void convertCollectionToArrayWithElementConversion() {
List<String> list = Arrays.asList("1", "2", "3");
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
Integer[] result = conversionService.convert(list, Integer[].class);
assertThat(result).containsExactly(1, 2, 3);
assertThat((int) result[0]).isEqualTo((int) Integer.valueOf(1));
assertThat((int) result[1]).isEqualTo((int) Integer.valueOf(2));
assertThat((int) result[2]).isEqualTo((int) Integer.valueOf(3));
}
@Test
@@ -511,30 +522,34 @@ class DefaultConversionServiceTests {
@Test
void convertStringToCollection() {
@SuppressWarnings("unchecked")
List<String> result = conversionService.convert("1,2,3", List.class);
assertThat(result).containsExactly("1", "2", "3");
List<?> result = conversionService.convert("1,2,3", List.class);
assertThat(result.size()).isEqualTo(3);
assertThat(result.get(0)).isEqualTo("1");
assertThat(result.get(1)).isEqualTo("2");
assertThat(result.get(2)).isEqualTo("3");
}
@Test
void convertStringToCollectionWithElementConversion() throws Exception {
@SuppressWarnings("unchecked")
List<Integer> result = (List<Integer>) conversionService.convert("1,2,3", TypeDescriptor.valueOf(String.class),
List<?> result = (List<?>) conversionService.convert("1,2,3", TypeDescriptor.valueOf(String.class),
new TypeDescriptor(getClass().getField("genericList")));
assertThat(result).containsExactly(1, 2, 3);
assertThat(result.size()).isEqualTo(3);
assertThat(result.get(0)).isEqualTo(1);
assertThat(result.get(1)).isEqualTo(2);
assertThat(result.get(2)).isEqualTo(3);
}
@Test
void convertEmptyStringToCollection() {
Collection<?> result = conversionService.convert("", Collection.class);
assertThat(result).isEmpty();
assertThat(result.size()).isEqualTo(0);
}
@Test
void convertCollectionToObject() {
List<Long> list = Collections.singletonList(3L);
Long result = conversionService.convert(list, Long.class);
assertThat(result).isEqualTo(3);
assertThat(result).isEqualTo(Long.valueOf(3));
}
@Test
@@ -16,34 +16,21 @@
package org.springframework.util;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.URI;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Currency;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
import java.util.regex.Pattern;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -237,7 +224,7 @@ class ObjectUtilsTests {
}
@Test
void addObjectToNullArray() {
void addObjectToNullArray() throws Exception {
String newElement = "foo";
String[] newArray = ObjectUtils.addObjectToArray(null, newElement);
assertThat(newArray).hasSize(1);
@@ -245,14 +232,14 @@ class ObjectUtilsTests {
}
@Test
void addNullObjectToNullArray() {
void addNullObjectToNullArray() throws Exception {
Object[] newArray = ObjectUtils.addObjectToArray(null, null);
assertThat(newArray).hasSize(1);
assertThat(newArray[0]).isNull();
}
@Test
void nullSafeEqualsWithArrays() {
void nullSafeEqualsWithArrays() throws Exception {
assertThat(ObjectUtils.nullSafeEquals(new String[] {"a", "b", "c"}, new String[] {"a", "b", "c"})).isTrue();
assertThat(ObjectUtils.nullSafeEquals(new int[] {1, 2, 3}, new int[] {1, 2, 3})).isTrue();
}
@@ -862,41 +849,6 @@ class ObjectUtilsTests {
assertThat(ObjectUtils.nullSafeConciseToString(null)).isEqualTo("null");
}
@Test
void nullSafeConciseToStringForEmptyOptional() {
Optional<String> optional = Optional.empty();
assertThat(ObjectUtils.nullSafeConciseToString(optional)).isEqualTo("Optional.empty");
}
@Test
void nullSafeConciseToStringForNonEmptyOptionals() {
Optional<Tropes> optionalEnum = Optional.of(Tropes.BAR);
String expected = "Optional[BAR]";
assertThat(ObjectUtils.nullSafeConciseToString(optionalEnum)).isEqualTo(expected);
String repeat100 = repeat("X", 100);
String repeat101 = repeat("X", 101);
Optional<String> optionalString = Optional.of(repeat100);
expected = String.format("Optional[%s]", repeat100);
assertThat(ObjectUtils.nullSafeConciseToString(optionalString)).isEqualTo(expected);
optionalString = Optional.of(repeat101);
expected = String.format("Optional[%s]", repeat100 + truncated);
assertThat(ObjectUtils.nullSafeConciseToString(optionalString)).isEqualTo(expected);
}
@Test
void nullSafeConciseToStringForNonEmptyOptionalCustomType() {
class CustomType {
}
CustomType customType = new CustomType();
Optional<CustomType> optional = Optional.of(customType);
String expected = String.format("Optional[%s]", ObjectUtils.nullSafeConciseToString(customType));
assertThat(ObjectUtils.nullSafeConciseToString(optional)).isEqualTo(expected);
}
@Test
void nullSafeConciseToStringForClass() {
assertThat(ObjectUtils.nullSafeConciseToString(String.class)).isEqualTo("java.lang.String");
@@ -929,19 +881,11 @@ class ObjectUtilsTests {
}
@Test
void nullSafeConciseToStringForPrimitivesAndWrappers() {
assertThat(ObjectUtils.nullSafeConciseToString(true)).isEqualTo("true");
assertThat(ObjectUtils.nullSafeConciseToString('X')).isEqualTo("X");
void nullSafeConciseToStringForNumber() {
assertThat(ObjectUtils.nullSafeConciseToString(42L)).isEqualTo("42");
assertThat(ObjectUtils.nullSafeConciseToString(99.1234D)).isEqualTo("99.1234");
}
@Test
void nullSafeConciseToStringForBigNumbers() {
assertThat(ObjectUtils.nullSafeConciseToString(BigInteger.valueOf(42L))).isEqualTo("42");
assertThat(ObjectUtils.nullSafeConciseToString(BigDecimal.valueOf(99.1234D))).isEqualTo("99.1234");
}
@Test
void nullSafeConciseToStringForDate() {
Date date = new Date();
@@ -960,30 +904,6 @@ class ObjectUtilsTests {
assertThat(ObjectUtils.nullSafeConciseToString(id)).isEqualTo(id.toString());
}
@Test
void nullSafeConciseToStringForFile() {
String path = "/tmp/file.txt".replace('/', File.separatorChar);
assertThat(ObjectUtils.nullSafeConciseToString(new File(path))).isEqualTo(path);
path = ("/tmp/" + repeat("xyz", 32)).replace('/', File.separatorChar);
assertThat(ObjectUtils.nullSafeConciseToString(new File(path)))
.hasSize(truncatedLength)
.startsWith(path.subSequence(0, 100))
.endsWith(truncated);
}
@Test
void nullSafeConciseToStringForPath() {
String path = "/tmp/file.txt".replace('/', File.separatorChar);
assertThat(ObjectUtils.nullSafeConciseToString(Paths.get(path))).isEqualTo(path);
path = ("/tmp/" + repeat("xyz", 32)).replace('/', File.separatorChar);
assertThat(ObjectUtils.nullSafeConciseToString(Paths.get(path)))
.hasSize(truncatedLength)
.startsWith(path.subSequence(0, 100))
.endsWith(truncated);
}
@Test
void nullSafeConciseToStringForURI() {
String uri = "https://www.example.com/?foo=1&bar=2&baz=3";
@@ -1008,100 +928,19 @@ class ObjectUtilsTests {
.endsWith(truncated);
}
@Test
void nullSafeConciseToStringForInetAddress() {
InetAddress localhost = getLocalhost();
assertThat(ObjectUtils.nullSafeConciseToString(localhost)).isEqualTo(localhost.toString());
}
private InetAddress getLocalhost() {
try {
return InetAddress.getLocalHost();
}
catch (UnknownHostException ex) {
return InetAddress.getLoopbackAddress();
}
}
@Test
void nullSafeConciseToStringForCharset() {
Charset charset = StandardCharsets.UTF_8;
assertThat(ObjectUtils.nullSafeConciseToString(charset)).isEqualTo(charset.name());
}
@Test
void nullSafeConciseToStringForCurrency() {
Currency currency = Currency.getInstance(Locale.US);
assertThat(ObjectUtils.nullSafeConciseToString(currency)).isEqualTo(currency.toString());
}
@Test
void nullSafeConciseToStringForLocale() {
assertThat(ObjectUtils.nullSafeConciseToString(Locale.GERMANY)).isEqualTo("de_DE");
}
@Test
void nullSafeConciseToStringForRegExPattern() {
Pattern pattern = Pattern.compile("^(foo|bar)$");
assertThat(ObjectUtils.nullSafeConciseToString(pattern)).isEqualTo(pattern.toString());
}
@Test
void nullSafeConciseToStringForTimeZone() {
TimeZone timeZone = TimeZone.getDefault();
assertThat(ObjectUtils.nullSafeConciseToString(timeZone)).isEqualTo(timeZone.getID());
}
@Test
void nullSafeConciseToStringForZoneId() {
ZoneId zoneId = ZoneId.systemDefault();
assertThat(ObjectUtils.nullSafeConciseToString(zoneId)).isEqualTo(zoneId.getId());
}
@Test
void nullSafeConciseToStringForEmptyArrays() {
assertThat(ObjectUtils.nullSafeConciseToString(new char[] {})).isEqualTo("{}");
assertThat(ObjectUtils.nullSafeConciseToString(new int[][] {})).isEqualTo("{}");
assertThat(ObjectUtils.nullSafeConciseToString(new String[] {})).isEqualTo("{}");
assertThat(ObjectUtils.nullSafeConciseToString(new Integer[][] {})).isEqualTo("{}");
}
@Test
void nullSafeConciseToStringForNonEmptyArrays() {
assertThat(ObjectUtils.nullSafeConciseToString(new char[] {'a'})).isEqualTo("{...}");
assertThat(ObjectUtils.nullSafeConciseToString(new int[][] {{1}, {2}})).isEqualTo("{...}");
assertThat(ObjectUtils.nullSafeConciseToString(new String[] {"enigma"})).isEqualTo("{...}");
assertThat(ObjectUtils.nullSafeConciseToString(new Integer[][] {{1}, {2}})).isEqualTo("{...}");
}
@Test
void nullSafeConciseToStringForEmptyCollections() {
List<String> list = Collections.emptyList();
Set<Integer> set = Collections.emptySet();
assertThat(ObjectUtils.nullSafeConciseToString(list)).isEqualTo("[]");
assertThat(ObjectUtils.nullSafeConciseToString(set)).isEqualTo("[]");
}
@Test
void nullSafeConciseToStringForNonEmptyCollections() {
List<String> list = Arrays.asList("a", "b");
Set<String> set = new HashSet<>();
set.add("foo");
assertThat(ObjectUtils.nullSafeConciseToString(list)).isEqualTo("[...]");
assertThat(ObjectUtils.nullSafeConciseToString(set)).isEqualTo("[...]");
}
@Test
void nullSafeConciseToStringForEmptyMaps() {
Map<String, Object> map = Collections.emptyMap();
assertThat(ObjectUtils.nullSafeConciseToString(map)).isEqualTo("{}");
}
@Test
void nullSafeConciseToStringForNonEmptyMaps() {
HashMap<String, Object> map = new HashMap<>();
map.put("foo", 42L);
assertThat(ObjectUtils.nullSafeConciseToString(map)).isEqualTo("{...}");
void nullSafeConciseToStringForArraysAndCollections() {
List<String> list = Arrays.asList("a", "b", "c");
assertThat(ObjectUtils.nullSafeConciseToString(new int[][] {{1, 2}, {3, 4}})).startsWith(prefix(int[][].class));
assertThat(ObjectUtils.nullSafeConciseToString(list.toArray(new Object[0]))).startsWith(prefix(Object[].class));
assertThat(ObjectUtils.nullSafeConciseToString(list.toArray(new String[0]))).startsWith(prefix(String[].class));
assertThat(ObjectUtils.nullSafeConciseToString(new ArrayList<>(list))).startsWith(prefix(ArrayList.class));
assertThat(ObjectUtils.nullSafeConciseToString(new HashSet<>(list))).startsWith(prefix(HashSet.class));
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2019 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.
@@ -102,47 +102,4 @@ public abstract class LogFactory {
return getLog(name);
}
// Just in case some code happens to call uncommon Commons Logging methods...
@Deprecated
public Object getAttribute(String name) {
return null;
}
@Deprecated
public String[] getAttributeNames() {
return new String[0];
}
@Deprecated
public void removeAttribute(String name) {
// do nothing
}
@Deprecated
public void setAttribute(String name, Object value) {
// do nothing
}
@Deprecated
public void release() {
// do nothing
}
@Deprecated
public static void release(ClassLoader classLoader) {
// do nothing
}
@Deprecated
public static void releaseAll() {
// do nothing
}
@Deprecated
public static String objectId(Object o) {
return (o == null ? "null" : o.getClass().getName() + "@" + System.identityHashCode(o));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2018 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.
@@ -47,9 +47,8 @@ public class LogFactoryService extends LogFactory {
}
// Just in case some code happens to rely on Commons Logging attributes...
// Just in case some code happens to call uncommon Commons Logging methods...
@Override
public void setAttribute(String name, Object value) {
if (value != null) {
this.attributes.put(name, value);
@@ -59,19 +58,19 @@ public class LogFactoryService extends LogFactory {
}
}
@Override
public void removeAttribute(String name) {
this.attributes.remove(name);
}
@Override
public Object getAttribute(String name) {
return this.attributes.get(name);
}
@Override
public String[] getAttributeNames() {
return this.attributes.keySet().toArray(new String[0]);
}
public void release() {
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -44,22 +44,11 @@ public class SQLWarningException extends UncategorizedDataAccessException {
super(msg, ex);
}
/**
* Return the underlying {@link SQLWarning}.
* @since 5.3.29
* Return the underlying SQLWarning.
*/
public SQLWarning getSQLWarning() {
public SQLWarning SQLWarning() {
return (SQLWarning) getCause();
}
/**
* Return the underlying {@link SQLWarning}.
* @deprecated as of 5.3.29, in favor of {@link #getSQLWarning()}
*/
@Deprecated
public SQLWarning SQLWarning() {
return getSQLWarning();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 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.
@@ -187,14 +187,12 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
/**
* Set whether we want to ignore JDBC statement warnings ({@link SQLWarning}).
* <p>Default is {@code true}, swallowing and logging all warnings. Switch this flag to
* {@code false} to make this JdbcTemplate throw a {@link SQLWarningException} instead
* (or chain the {@link SQLWarning} into the primary {@link SQLException}, if any).
* @see Statement#getWarnings()
* Set whether we want to ignore SQLWarnings.
* <p>Default is "true", swallowing and logging all warnings. Switch this flag
* to "false" to make the JdbcTemplate throw an SQLWarningException instead.
* @see java.sql.SQLWarning
* @see org.springframework.jdbc.SQLWarningException
* @see #handleWarnings(Statement)
* @see #handleWarnings
*/
public void setIgnoreWarnings(boolean ignoreWarnings) {
this.ignoreWarnings = ignoreWarnings;
@@ -387,9 +385,6 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
catch (SQLException ex) {
// Release Connection early, to avoid potential connection pool deadlock
// in the case when the exception translator hasn't been initialized yet.
if (stmt != null) {
handleWarnings(stmt, ex);
}
String sql = getSql(action);
JdbcUtils.closeStatement(stmt);
stmt = null;
@@ -663,9 +658,6 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
if (psc instanceof ParameterDisposer) {
((ParameterDisposer) psc).cleanupParameters();
}
if (ps != null) {
handleWarnings(ps, ex);
}
String sql = getSql(psc);
psc = null;
JdbcUtils.closeStatement(ps);
@@ -1205,9 +1197,6 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
if (csc instanceof ParameterDisposer) {
((ParameterDisposer) csc).cleanupParameters();
}
if (cs != null) {
handleWarnings(cs, ex);
}
String sql = getSql(csc);
csc = null;
JdbcUtils.closeStatement(cs);
@@ -1505,44 +1494,13 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
}
/**
* Handle warnings before propagating a primary {@code SQLException}
* from executing the given statement.
* <p>Calls regular {@link #handleWarnings(Statement)} but catches
* {@link SQLWarningException} in order to chain the {@link SQLWarning}
* into the primary exception instead.
* Throw an SQLWarningException if we're not ignoring warnings,
* otherwise log the warnings at debug level.
* @param stmt the current JDBC statement
* @param ex the primary exception after failed statement execution
* @since 5.3.29
* @see #handleWarnings(Statement)
* @see SQLException#setNextException
* @throws SQLWarningException if not ignoring warnings
* @see org.springframework.jdbc.SQLWarningException
*/
protected void handleWarnings(Statement stmt, SQLException ex) {
try {
handleWarnings(stmt);
}
catch (SQLWarningException nonIgnoredWarning) {
ex.setNextException(nonIgnoredWarning.getSQLWarning());
}
catch (SQLException warningsEx) {
logger.debug("Failed to retrieve warnings", warningsEx);
}
catch (Throwable warningsEx) {
logger.debug("Failed to process warnings", warningsEx);
}
}
/**
* Handle the warnings for the given JDBC statement, if any.
* <p>Throws a {@link SQLWarningException} if we're not ignoring warnings,
* otherwise logs the warnings at debug level.
* @param stmt the current JDBC statement
* @throws SQLException in case of warnings retrieval failure
* @throws SQLWarningException for a concrete warning to raise
* (when not ignoring warnings)
* @see #setIgnoreWarnings
* @see #handleWarnings(SQLWarning)
*/
protected void handleWarnings(Statement stmt) throws SQLException, SQLWarningException {
protected void handleWarnings(Statement stmt) throws SQLException {
if (isIgnoreWarnings()) {
if (logger.isDebugEnabled()) {
SQLWarning warningToLog = stmt.getWarnings();
@@ -1559,7 +1517,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
}
/**
* Throw a {@link SQLWarningException} if encountering an actual warning.
* Throw an SQLWarningException if encountering an actual warning.
* @param warning the warnings object from the current statement.
* May be {@code null}, in which case this method does nothing.
* @throws SQLWarningException in case of an actual warning to be raised
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 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.
@@ -172,7 +172,7 @@
<value>2601,2627</value>
</property>
<property name="dataIntegrityViolationCodes">
<value>544,2628,8114,8115</value>
<value>544,8114,8115</value>
</property>
<property name="dataAccessResourceFailureCodes">
<value>4060</value>
@@ -125,19 +125,18 @@ public abstract class AbstractJmsListeningContainer extends JmsDestinationAccess
}
/**
* Specify the lifecycle phase in which this container should be started and stopped.
* <p>The startup order proceeds from lowest to highest, and the shutdown order
* is the reverse of that. The default is {@link #DEFAULT_PHASE} meaning that
* this container starts as late as possible and stops as soon as possible.
* @see SmartLifecycle#getPhase()
* Specify the phase in which this container should be started and
* stopped. The startup order proceeds from lowest to highest, and
* the shutdown order is the reverse of that. By default this value
* is Integer.MAX_VALUE meaning that this container starts as late
* as possible and stops as soon as possible.
*/
public void setPhase(int phase) {
this.phase = phase;
}
/**
* Return the lifecycle phase in which this container will be started and stopped.
* @see #setPhase
* Return the phase in which this container will be started and stopped.
*/
@Override
public int getPhase() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 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.
@@ -212,7 +212,7 @@ public class HandlerMethod {
/**
* If the bean method is a bridge method, this method returns the bridged
* (user-defined) method. Otherwise, it returns the same method as {@link #getMethod()}.
* (user-defined) method. Otherwise it returns the same method as {@link #getMethod()}.
*/
protected Method getBridgedMethod() {
return this.bridgedMethod;
@@ -298,8 +298,8 @@ public class HandlerMethod {
* Return a short representation of this handler method for log message purposes.
*/
public String getShortLogMessage() {
return getBeanType().getSimpleName() + "#" + this.method.getName() +
"[" + this.method.getParameterCount() + " args]";
int args = this.method.getParameterCount();
return getBeanType().getSimpleName() + "#" + this.method.getName() + "[" + args + " args]";
}
@@ -365,11 +365,13 @@ public class HandlerMethod {
}
protected String formatInvokeError(String text, Object[] args) {
String formattedArgs = IntStream.range(0, args.length)
.mapToObj(i -> (args[i] != null ?
"[" + i + "] [type=" + args[i].getClass().getName() + "] [value=" + args[i] + "]" :
"[" + i + "] [null]"))
.collect(Collectors.joining(",\n", " ", " "));
return text + "\n" +
"Endpoint [" + getBeanType().getName() + "]\n" +
"Method [" + getBridgedMethod().toGenericString() + "] " +
@@ -613,12 +613,11 @@ public class ResolvableMethod {
private static class MethodInvocationInterceptor implements MethodInterceptor, InvocationHandler {
@Nullable
private Method invokedMethod;
@Override
@Nullable
public Object intercept(Object object, Method method, @Nullable Object[] args, @Nullable MethodProxy proxy) {
public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) {
if (ReflectionUtils.isObjectMethod(method)) {
return ReflectionUtils.invokeMethod(method, object, args);
}
@@ -630,11 +629,10 @@ public class ResolvableMethod {
@Override
@Nullable
public Object invoke(Object proxy, Method method, @Nullable Object[] args) {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return intercept(proxy, method, args, null);
}
@Nullable
Method getInvokedMethod() {
return this.invokedMethod;
}
@@ -100,11 +100,13 @@ import org.springframework.util.Assert;
* @author Juergen Hoeller
* @since 4.2
* @see #setSessionFactory
* @see #setDataSource
* @see SessionFactory#getCurrentSession()
* @see DataSourceUtils#getConnection
* @see DataSourceUtils#releaseConnection
* @see org.springframework.jdbc.core.JdbcTemplate
* @see org.springframework.jdbc.support.JdbcTransactionManager
* @see org.springframework.orm.jpa.JpaTransactionManager
* @see org.springframework.orm.jpa.vendor.HibernateJpaDialect
* @see org.springframework.transaction.jta.JtaTransactionManager
*/
@SuppressWarnings("serial")
public class HibernateTransactionManager extends AbstractPlatformTransactionManager
@@ -269,11 +271,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
* @see Connection#setHoldability
* @see ResultSet#HOLD_CURSORS_OVER_COMMIT
* @see #disconnectOnCompletion(Session)
* @deprecated as of 5.3.29 since Hibernate 5.x aggressively closes ResultSets on commit,
* making it impossible to rely on ResultSet holdability. Also, Spring does not provide
* an equivalent setting on {@link org.springframework.orm.jpa.JpaTransactionManager}.
*/
@Deprecated
public void setAllowResultAccessAfterCompletion(boolean allowResultAccessAfterCompletion) {
this.allowResultAccessAfterCompletion = allowResultAccessAfterCompletion;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 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.
@@ -180,23 +180,14 @@ public final class SpringBeanContainer implements BeanContainer {
try {
if (lifecycleOptions.useJpaCompliantCreation()) {
if (this.beanFactory.containsBean(name)) {
Object bean = this.beanFactory.autowire(beanType, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);
this.beanFactory.autowireBeanProperties(bean, AutowireCapableBeanFactory.AUTOWIRE_NO, false);
this.beanFactory.applyBeanPropertyValues(bean, name);
bean = this.beanFactory.initializeBean(bean, name);
return new SpringContainedBean<>(bean, beanInstance -> this.beanFactory.destroyBean(name, beanInstance));
}
else {
return new SpringContainedBean<>(
this.beanFactory.createBean(beanType, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false),
this.beanFactory::destroyBean);
}
Object bean = this.beanFactory.autowire(beanType, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);
this.beanFactory.autowireBeanProperties(bean, AutowireCapableBeanFactory.AUTOWIRE_NO, false);
this.beanFactory.applyBeanPropertyValues(bean, name);
bean = this.beanFactory.initializeBean(bean, name);
return new SpringContainedBean<>(bean, beanInstance -> this.beanFactory.destroyBean(name, beanInstance));
}
else {
return (this.beanFactory.containsBean(name) ?
new SpringContainedBean<>(this.beanFactory.getBean(name, beanType)) :
new SpringContainedBean<>(this.beanFactory.getBean(beanType)));
return new SpringContainedBean<>(this.beanFactory.getBean(name, beanType));
}
}
catch (BeansException ex) {
@@ -29,6 +29,7 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.reactive.AbstractReactiveTransactionManager;
import org.springframework.transaction.reactive.GenericReactiveTransaction;
import org.springframework.transaction.reactive.TransactionSynchronizationManager;
@@ -161,7 +162,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
}
@Override
protected Object doGetTransaction(TransactionSynchronizationManager synchronizationManager) {
protected Object doGetTransaction(TransactionSynchronizationManager synchronizationManager) throws TransactionException {
ConnectionFactoryTransactionObject txObject = new ConnectionFactoryTransactionObject();
ConnectionHolder conHolder = (ConnectionHolder) synchronizationManager.getResource(obtainConnectionFactory());
txObject.setConnectionHolder(conHolder, false);
@@ -177,7 +178,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
@SuppressWarnings("deprecation")
@Override
protected Mono<Void> doBegin(TransactionSynchronizationManager synchronizationManager, Object transaction,
TransactionDefinition definition) {
TransactionDefinition definition) throws TransactionException {
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) transaction;
@@ -242,7 +243,9 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
}
@Override
protected Mono<Object> doSuspend(TransactionSynchronizationManager synchronizationManager, Object transaction) {
protected Mono<Object> doSuspend(TransactionSynchronizationManager synchronizationManager, Object transaction)
throws TransactionException {
return Mono.defer(() -> {
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) transaction;
txObject.setConnectionHolder(null);
@@ -252,7 +255,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
@Override
protected Mono<Void> doResume(TransactionSynchronizationManager synchronizationManager,
@Nullable Object transaction, Object suspendedResources) {
@Nullable Object transaction, Object suspendedResources) throws TransactionException {
return Mono.defer(() -> {
synchronizationManager.bindResource(obtainConnectionFactory(), suspendedResources);
@@ -262,7 +265,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
@Override
protected Mono<Void> doCommit(TransactionSynchronizationManager TransactionSynchronizationManager,
GenericReactiveTransaction status) {
GenericReactiveTransaction status) throws TransactionException {
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) status.getTransaction();
Connection connection = txObject.getConnectionHolder().getConnection();
@@ -275,7 +278,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
@Override
protected Mono<Void> doRollback(TransactionSynchronizationManager TransactionSynchronizationManager,
GenericReactiveTransaction status) {
GenericReactiveTransaction status) throws TransactionException {
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) status.getTransaction();
Connection connection = txObject.getConnectionHolder().getConnection();
@@ -288,7 +291,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
@Override
protected Mono<Void> doSetRollbackOnly(TransactionSynchronizationManager synchronizationManager,
GenericReactiveTransaction status) {
GenericReactiveTransaction status) throws TransactionException {
return Mono.fromRunnable(() -> {
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) status.getTransaction();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 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.
@@ -31,10 +31,10 @@ import org.springframework.lang.Nullable;
* template methods for specific states of the underlying transaction,
* for example: begin, suspend, resume, commit.
*
* <p>A classic implementation of this strategy interface is
* {@link org.springframework.transaction.jta.JtaTransactionManager}. However,
* in common single-resource scenarios, Spring's specific transaction managers
* for e.g. JDBC, JPA, JMS are preferred choices.
* <p>The default implementations of this strategy interface are
* {@link org.springframework.transaction.jta.JtaTransactionManager} and
* {@link org.springframework.jdbc.datasource.DataSourceTransactionManager},
* which can serve as an implementation guide for other transaction strategies.
*
* @author Rod Johnson
* @author Juergen Hoeller
@@ -81,9 +81,12 @@ public interface PlatformTransactionManager extends TransactionManager {
* <p>Note that when the commit call completes, no matter if normally or
* throwing an exception, the transaction must be fully completed and
* cleaned up. No rollback call should be expected in such a case.
* <p>Depending on the concrete transaction manager setup, {@code commit}
* may propagate {@link org.springframework.dao.DataAccessException} as well,
* either from before-commit flushes or from the actual commit step.
* <p>If this method throws an exception other than a TransactionException,
* then some before-commit error caused the commit attempt to fail. For
* example, an O/R Mapping tool might have tried to flush changes to the
* database right before commit, with the resulting DataAccessException
* causing the transaction to fail. The original exception will be
* propagated to the caller of this commit method in such a case.
* @param status object returned by the {@code getTransaction} method
* @throws UnexpectedRollbackException in case of an unexpected rollback
* that the transaction coordinator initiated
@@ -107,8 +110,6 @@ public interface PlatformTransactionManager extends TransactionManager {
* The transaction will already have been completed and cleaned up when commit
* returns, even in case of a commit exception. Consequently, a rollback call
* after commit failure will lead to an IllegalTransactionStateException.
* <p>Depending on the concrete transaction manager setup, {@code rollback}
* may propagate {@link org.springframework.dao.DataAccessException} as well.
* @param status object returned by the {@code getTransaction} method
* @throws TransactionSystemException in case of rollback or system errors
* (typically caused by fundamental resource failures)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 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.
@@ -46,8 +46,6 @@ public interface ReactiveTransactionManager extends TransactionManager {
* <p>An exception to the above rule is the read-only flag, which should be
* ignored if no explicit read-only mode is supported. Essentially, the
* read-only flag is just a hint for potential optimization.
* <p>Note: In contrast to {@link PlatformTransactionManager}, exceptions
* are propagated through the reactive pipeline returned from this method.
* @param definition the TransactionDefinition instance,
* describing propagation behavior, isolation level, timeout etc.
* @return transaction status object representing the new or current transaction
@@ -60,7 +58,8 @@ public interface ReactiveTransactionManager extends TransactionManager {
* @see TransactionDefinition#getTimeout
* @see TransactionDefinition#isReadOnly
*/
Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition definition);
Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
/**
* Commit the given transaction, with regard to its status. If the transaction
@@ -70,12 +69,14 @@ public interface ReactiveTransactionManager extends TransactionManager {
* has been suspended to be able to create a new one, resume the previous
* transaction after committing the new one.
* <p>Note that when the commit call completes, no matter if normally or
* propagating an exception, the transaction must be fully completed and
* throwing an exception, the transaction must be fully completed and
* cleaned up. No rollback call should be expected in such a case.
* <p>Note: In contrast to {@link PlatformTransactionManager}, exceptions
* are propagated through the reactive pipeline returned from this method.
* Also, depending on the transaction manager implementation, {@code commit}
* may propagate {@link org.springframework.dao.DataAccessException} as well.
* <p>If this method throws an exception other than a TransactionException,
* then some before-commit error caused the commit attempt to fail. For
* example, an O/R Mapping tool might have tried to flush changes to the
* database right before commit, with the resulting DataAccessException
* causing the transaction to fail. The original exception will be
* propagated to the caller of this commit method in such a case.
* @param transaction object returned by the {@code getTransaction} method
* @throws UnexpectedRollbackException in case of an unexpected rollback
* that the transaction coordinator initiated
@@ -87,7 +88,7 @@ public interface ReactiveTransactionManager extends TransactionManager {
* is already completed (that is, committed or rolled back)
* @see ReactiveTransaction#setRollbackOnly
*/
Mono<Void> commit(ReactiveTransaction transaction);
Mono<Void> commit(ReactiveTransaction transaction) throws TransactionException;
/**
* Perform a rollback of the given transaction.
@@ -95,20 +96,16 @@ public interface ReactiveTransactionManager extends TransactionManager {
* participation in the surrounding transaction. If a previous transaction
* has been suspended to be able to create a new one, resume the previous
* transaction after rolling back the new one.
* <p><b>Do not call rollback on a transaction if commit failed.</b>
* <p><b>Do not call rollback on a transaction if commit threw an exception.</b>
* The transaction will already have been completed and cleaned up when commit
* returns, even in case of a commit exception. Consequently, a rollback call
* after commit failure will lead to an IllegalTransactionStateException.
* <p>Note: In contrast to {@link PlatformTransactionManager}, exceptions
* are propagated through the reactive pipeline returned from this method.
* Also, depending on the transaction manager implementation, {@code rollback}
* may propagate {@link org.springframework.dao.DataAccessException} as well.
* @param transaction object returned by the {@code getTransaction} method
* @throws TransactionSystemException in case of rollback or system errors
* (typically caused by fundamental resource failures)
* @throws IllegalTransactionStateException if the given transaction
* is already completed (that is, committed or rolled back)
*/
Mono<Void> rollback(ReactiveTransaction transaction);
Mono<Void> rollback(ReactiveTransaction transaction) throws TransactionException;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -95,7 +95,9 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* @see #doBegin
*/
@Override
public final Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition definition) {
public final Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// Use defaults if no transaction definition given.
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
@@ -163,7 +165,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* Create a ReactiveTransaction for an existing transaction.
*/
private Mono<ReactiveTransaction> handleExistingTransaction(TransactionSynchronizationManager synchronizationManager,
TransactionDefinition definition, Object transaction, boolean debugEnabled) {
TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException {
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
return Mono.error(new IllegalTransactionStateException(
@@ -275,7 +277,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* @see #resume
*/
private Mono<SuspendedResourcesHolder> suspend(TransactionSynchronizationManager synchronizationManager,
@Nullable Object transaction) {
@Nullable Object transaction) throws TransactionException {
if (synchronizationManager.isSynchronizationActive()) {
Mono<List<TransactionSynchronization>> suspendedSynchronizations = doSuspendSynchronization(synchronizationManager);
@@ -323,7 +325,8 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* @see #suspend
*/
private Mono<Void> resume(TransactionSynchronizationManager synchronizationManager,
@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder) {
@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)
throws TransactionException {
Mono<Void> resume = Mono.empty();
@@ -400,7 +403,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* @see #rollback
*/
@Override
public final Mono<Void> commit(ReactiveTransaction transaction) {
public final Mono<Void> commit(ReactiveTransaction transaction) throws TransactionException {
if (transaction.isCompleted()) {
return Mono.error(new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction"));
@@ -423,9 +426,10 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* Rollback-only flags have already been checked and applied.
* @param synchronizationManager the synchronization manager bound to the current transaction
* @param status object representing the transaction
* @throws TransactionException in case of commit failure
*/
private Mono<Void> processCommit(TransactionSynchronizationManager synchronizationManager,
GenericReactiveTransaction status) {
GenericReactiveTransaction status) throws TransactionException {
AtomicBoolean beforeCompletionInvoked = new AtomicBoolean();
@@ -483,7 +487,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* @see #doSetRollbackOnly
*/
@Override
public final Mono<Void> rollback(ReactiveTransaction transaction) {
public final Mono<Void> rollback(ReactiveTransaction transaction) throws TransactionException {
if (transaction.isCompleted()) {
return Mono.error(new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction"));
@@ -499,6 +503,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* The completed flag has already been checked.
* @param synchronizationManager the synchronization manager bound to the current transaction
* @param status object representing the transaction
* @throws TransactionException in case of rollback failure
*/
private Mono<Void> processRollback(TransactionSynchronizationManager synchronizationManager,
GenericReactiveTransaction status) {
@@ -537,10 +542,11 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* @param synchronizationManager the synchronization manager bound to the current transaction
* @param status object representing the transaction
* @param ex the thrown application exception or error
* @throws TransactionException in case of rollback failure
* @see #doRollback
*/
private Mono<Void> doRollbackOnCommitException(TransactionSynchronizationManager synchronizationManager,
GenericReactiveTransaction status, Throwable ex) {
GenericReactiveTransaction status, Throwable ex) throws TransactionException {
return Mono.defer(() -> {
if (status.isNewTransaction()) {
@@ -708,12 +714,14 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* @return the current transaction object
* @throws org.springframework.transaction.CannotCreateTransactionException
* if transaction support is not available
* @throws TransactionException in case of lookup or system errors
* @see #doBegin
* @see #doCommit
* @see #doRollback
* @see GenericReactiveTransaction#getTransaction
*/
protected abstract Object doGetTransaction(TransactionSynchronizationManager synchronizationManager);
protected abstract Object doGetTransaction(TransactionSynchronizationManager synchronizationManager)
throws TransactionException;
/**
* Check if the given transaction object indicates an existing transaction
@@ -727,9 +735,10 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* Subclasses are of course encouraged to provide such support.
* @param transaction the transaction object returned by doGetTransaction
* @return if there is an existing transaction
* @throws TransactionException in case of system errors
* @see #doGetTransaction
*/
protected boolean isExistingTransaction(Object transaction) {
protected boolean isExistingTransaction(Object transaction) throws TransactionException {
return false;
}
@@ -748,11 +757,12 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* @param transaction the transaction object returned by {@code doGetTransaction}
* @param definition a TransactionDefinition instance, describing propagation
* behavior, isolation level, read-only flag, timeout, and transaction name
* @throws TransactionException in case of creation or system errors
* @throws org.springframework.transaction.NestedTransactionNotSupportedException
* if the underlying transaction does not support nesting (e.g. through savepoints)
*/
protected abstract Mono<Void> doBegin(TransactionSynchronizationManager synchronizationManager,
Object transaction, TransactionDefinition definition);
Object transaction, TransactionDefinition definition) throws TransactionException;
/**
* Suspend the resources of the current transaction.
@@ -765,10 +775,11 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* (will be kept unexamined for passing it into doResume)
* @throws org.springframework.transaction.TransactionSuspensionNotSupportedException
* if suspending is not supported by the transaction manager implementation
* @throws TransactionException in case of system errors
* @see #doResume
*/
protected Mono<Object> doSuspend(TransactionSynchronizationManager synchronizationManager,
Object transaction) {
Object transaction) throws TransactionException {
throw new TransactionSuspensionNotSupportedException(
"Transaction manager [" + getClass().getName() + "] does not support transaction suspension");
@@ -785,10 +796,11 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* as returned by doSuspend
* @throws org.springframework.transaction.TransactionSuspensionNotSupportedException
* if suspending is not supported by the transaction manager implementation
* @throws TransactionException in case of system errors
* @see #doSuspend
*/
protected Mono<Void> doResume(TransactionSynchronizationManager synchronizationManager,
@Nullable Object transaction, Object suspendedResources) {
@Nullable Object transaction, Object suspendedResources) throws TransactionException {
throw new TransactionSuspensionNotSupportedException(
"Transaction manager [" + getClass().getName() + "] does not support transaction suspension");
@@ -818,10 +830,11 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* contained in the passed-in status.
* @param synchronizationManager the synchronization manager bound to the current transaction
* @param status the status representation of the transaction
* @throws TransactionException in case of commit or system errors
* @see GenericReactiveTransaction#getTransaction
*/
protected abstract Mono<Void> doCommit(TransactionSynchronizationManager synchronizationManager,
GenericReactiveTransaction status);
GenericReactiveTransaction status) throws TransactionException;
/**
* Perform an actual rollback of the given transaction.
@@ -830,10 +843,11 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* will be performed on the transaction object contained in the passed-in status.
* @param synchronizationManager the synchronization manager bound to the current transaction
* @param status the status representation of the transaction
* @throws TransactionException in case of system errors
* @see GenericReactiveTransaction#getTransaction
*/
protected abstract Mono<Void> doRollback(TransactionSynchronizationManager synchronizationManager,
GenericReactiveTransaction status);
GenericReactiveTransaction status) throws TransactionException;
/**
* Set the given transaction rollback-only. Only called on rollback
@@ -843,9 +857,10 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* supported. Subclasses are of course encouraged to provide such support.
* @param synchronizationManager the synchronization manager bound to the current transaction
* @param status the status representation of the transaction
* @throws TransactionException in case of system errors
*/
protected Mono<Void> doSetRollbackOnly(TransactionSynchronizationManager synchronizationManager,
GenericReactiveTransaction status) {
GenericReactiveTransaction status) throws TransactionException {
throw new IllegalTransactionStateException(
"Participating in existing transactions is not supported - when 'isExistingTransaction' " +
@@ -863,12 +878,13 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
* @param synchronizationManager the synchronization manager bound to the current transaction
* @param transaction the transaction object returned by {@code doGetTransaction}
* @param synchronizations a List of TransactionSynchronization objects
* @throws TransactionException in case of system errors
* @see #invokeAfterCompletion(TransactionSynchronizationManager, List, int)
* @see TransactionSynchronization#afterCompletion(int)
* @see TransactionSynchronization#STATUS_UNKNOWN
*/
protected Mono<Void> registerAfterCompletionWithExistingTransaction(TransactionSynchronizationManager synchronizationManager,
Object transaction, List<TransactionSynchronization> synchronizations) {
Object transaction, List<TransactionSynchronization> synchronizations) throws TransactionException {
logger.debug("Cannot register Spring after-completion synchronization with existing transaction - " +
"processing Spring after-completion callbacks immediately, with outcome status 'unknown'");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 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.
@@ -85,7 +85,7 @@ abstract class TransactionSynchronizationUtils {
public static Mono<Void> triggerBeforeCompletion(Collection<TransactionSynchronization> synchronizations) {
return Flux.fromIterable(synchronizations)
.concatMap(TransactionSynchronization::beforeCompletion).onErrorContinue((t, o) ->
logger.error("TransactionSynchronization.beforeCompletion threw exception", t)).then();
logger.debug("TransactionSynchronization.beforeCompletion threw exception", t)).then();
}
/**
@@ -115,7 +115,7 @@ abstract class TransactionSynchronizationUtils {
Collection<TransactionSynchronization> synchronizations, int completionStatus) {
return Flux.fromIterable(synchronizations).concatMap(it -> it.afterCompletion(completionStatus))
.onErrorContinue((t, o) -> logger.error("TransactionSynchronization.afterCompletion threw exception", t)).then();
.onErrorContinue((t, o) -> logger.debug("TransactionSynchronization.afterCompletion threw exception", t)).then();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -108,7 +108,7 @@ public abstract class TransactionSynchronizationUtils {
synchronization.beforeCompletion();
}
catch (Throwable ex) {
logger.error("TransactionSynchronization.beforeCompletion threw exception", ex);
logger.debug("TransactionSynchronization.beforeCompletion threw exception", ex);
}
}
}
@@ -172,7 +172,7 @@ public abstract class TransactionSynchronizationUtils {
synchronization.afterCompletion(completionStatus);
}
catch (Throwable ex) {
logger.error("TransactionSynchronization.afterCompletion threw exception", ex);
logger.debug("TransactionSynchronization.afterCompletion threw exception", ex);
}
}
}
@@ -580,7 +580,7 @@ public class Jackson2ObjectMapperBuilder {
* @see com.fasterxml.jackson.databind.Module
*/
public Jackson2ObjectMapperBuilder modulesToInstall(Module... modules) {
this.modules = new ArrayList<>(Arrays.asList(modules));
this.modules = Arrays.asList(modules);
this.findWellKnownModules = true;
return this;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 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.
@@ -57,7 +57,7 @@ public class ServletContextResource extends AbstractFileResolvingResource implem
/**
* Create a new {@code ServletContextResource} for the given path.
* Create a new ServletContextResource.
* <p>The Servlet spec requires that resource paths start with a slash,
* even if many containers accept paths without leading slash too.
* Consequently, the given path will be prepended with a slash if it
@@ -94,7 +94,6 @@ public class ServletContextResource extends AbstractFileResolvingResource implem
return this.path;
}
/**
* This implementation checks {@code ServletContext.getResource}.
* @see javax.servlet.ServletContext#getResource(String)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2022 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.
@@ -218,7 +218,6 @@ public class HandlerMethod {
this.description = handlerMethod.description;
}
private MethodParameter[] initMethodParameters() {
int count = this.bridgedMethod.getParameterCount();
MethodParameter[] result = new MethodParameter[count];
@@ -249,7 +248,7 @@ public class HandlerMethod {
for (Class<?> paramType : method.getParameterTypes()) {
joiner.add(paramType.getSimpleName());
}
return beanType.getName() + "#" + method.getName() + joiner;
return beanType.getName() + "#" + method.getName() + joiner.toString();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 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,7 +17,6 @@
package org.springframework.web.util.pattern;
import org.springframework.http.server.PathContainer;
import org.springframework.util.StringUtils;
/**
* Parser for URI path patterns producing {@link PathPattern} instances that can
@@ -97,17 +96,6 @@ public class PathPatternParser {
}
/**
* Prepare the given pattern for use in matching to full URL paths.
* <p>By default, prepend a leading slash if needed for non-empty patterns.
* @param pattern the pattern to initialize
* @return the updated pattern
* @since 5.2.25
*/
public String initFullPathPattern(String pattern) {
return (StringUtils.hasLength(pattern) && !pattern.startsWith("/") ? "/" + pattern : pattern);
}
/**
* Process the path pattern content, a character at a time, breaking it into
* path elements around separator boundaries and verifying the structure at each
@@ -229,6 +229,26 @@ class Jackson2ObjectMapperBuilderTests {
Jackson2ObjectMapperBuilder.json().timeZone(zoneId).build());
}
@Test
void modules() {
NumberSerializer serializer1 = new NumberSerializer(Integer.class);
SimpleModule module = new SimpleModule();
module.addSerializer(Integer.class, serializer1);
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().modules(module).build();
Serializers serializers = getSerializerFactoryConfig(objectMapper).serializers().iterator().next();
assertThat(serializers.findSerializer(null, SimpleType.construct(Integer.class), null)).isSameAs(serializer1);
}
@Test
void modulesWithConsumer() {
NumberSerializer serializer1 = new NumberSerializer(Integer.class);
SimpleModule module = new SimpleModule();
module.addSerializer(Integer.class, serializer1);
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().modules(list -> list.add(module) ).build();
Serializers serializers = getSerializerFactoryConfig(objectMapper).serializers().iterator().next();
assertThat(serializers.findSerializer(null, SimpleType.construct(Integer.class), null)).isSameAs(serializer1);
}
@Test
void modulesToInstallByClass() {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json()
@@ -331,15 +351,14 @@ class Jackson2ObjectMapperBuilderTests {
barModule.addSerializer(new BarSerializer());
builder.modulesToInstall(fooModule, barModule);
ObjectMapper objectMapper = builder.build();
assertThat(StreamSupport
.stream(getSerializerFactoryConfig(objectMapper).serializers().spliterator(), false)
.filter(s -> s.findSerializer(null, SimpleType.construct(Foo.class), null) != null)
.count()).isEqualTo(1);
.stream(getSerializerFactoryConfig(objectMapper).serializers().spliterator(), false)
.filter(s -> s.findSerializer(null, SimpleType.construct(Foo.class), null) != null)
.count()).isEqualTo(1);
assertThat(StreamSupport
.stream(getSerializerFactoryConfig(objectMapper).serializers().spliterator(), false)
.filter(s -> s.findSerializer(null, SimpleType.construct(Bar.class), null) != null)
.count()).isEqualTo(1);
.stream(getSerializerFactoryConfig(objectMapper).serializers().spliterator(), false)
.filter(s -> s.findSerializer(null, SimpleType.construct(Bar.class), null) != null)
.count()).isEqualTo(1);
}
private static SerializerFactoryConfig getSerializerFactoryConfig(ObjectMapper objectMapper) {
@@ -350,38 +369,6 @@ class Jackson2ObjectMapperBuilderTests {
return ((BasicDeserializerFactory) objectMapper.getDeserializationContext().getFactory()).getFactoryConfig();
}
@Test
void modules() {
NumberSerializer serializer1 = new NumberSerializer(Integer.class);
SimpleModule module = new SimpleModule();
module.addSerializer(Integer.class, serializer1);
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().modules(module).build();
Serializers serializers = getSerializerFactoryConfig(objectMapper).serializers().iterator().next();
assertThat(serializers.findSerializer(null, SimpleType.construct(Integer.class), null)).isSameAs(serializer1);
}
@Test
void modulesWithConsumer() {
NumberSerializer serializer1 = new NumberSerializer(Integer.class);
SimpleModule module = new SimpleModule();
module.addSerializer(Integer.class, serializer1);
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().modules(list -> list.add(module) ).build();
Serializers serializers = getSerializerFactoryConfig(objectMapper).serializers().iterator().next();
assertThat(serializers.findSerializer(null, SimpleType.construct(Integer.class), null)).isSameAs(serializer1);
}
@Test
void modulesWithConsumerAfterModulesToInstall() {
NumberSerializer serializer1 = new NumberSerializer(Integer.class);
SimpleModule module = new SimpleModule();
module.addSerializer(Integer.class, serializer1);
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json()
.modulesToInstall(new JavaTimeModule())
.modules(list -> list.add(module) ).build();
Serializers serializers = getSerializerFactoryConfig(objectMapper).serializers().iterator().next();
assertThat(serializers.findSerializer(null, SimpleType.construct(Integer.class), null)).isSameAs(serializer1);
}
@Test
void propertyNamingStrategy() {
PropertyNamingStrategy strategy = new PropertyNamingStrategy.SnakeCaseStrategy();
@@ -394,7 +381,7 @@ class Jackson2ObjectMapperBuilderTests {
void serializerByType() {
JsonSerializer<Number> serializer = new NumberSerializer(Integer.class);
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json()
.modules(new ArrayList<>()) // disable well-known modules detection
.modules(new ArrayList<>()) // Disable well-known modules detection
.serializerByType(Boolean.class, serializer)
.build();
assertThat(getSerializerFactoryConfig(objectMapper).hasSerializers()).isTrue();
@@ -406,7 +393,7 @@ class Jackson2ObjectMapperBuilderTests {
void deserializerByType() throws JsonMappingException {
JsonDeserializer<Date> deserializer = new DateDeserializers.DateDeserializer();
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json()
.modules(new ArrayList<>()) // disable well-known modules detection
.modules(new ArrayList<>()) // Disable well-known modules detection
.deserializerByType(Date.class, deserializer)
.build();
assertThat(getDeserializerFactoryConfig(objectMapper).hasDeserializers()).isTrue();
@@ -485,7 +472,7 @@ class Jackson2ObjectMapperBuilderTests {
JsonSerializer<Number> serializer2 = new NumberSerializer(Integer.class);
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json()
.modules(new ArrayList<>()) // disable well-known modules detection
.modules(new ArrayList<>()) // Disable well-known modules detection
.serializers(serializer1)
.serializersByType(Collections.singletonMap(Boolean.class, serializer2))
.deserializersByType(deserializerMap)
@@ -617,12 +617,11 @@ public class ResolvableMethod {
private static class MethodInvocationInterceptor implements MethodInterceptor, InvocationHandler {
@Nullable
private Method invokedMethod;
@Override
@Nullable
public Object intercept(Object object, Method method, @Nullable Object[] args, @Nullable MethodProxy proxy) {
public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) {
if (ReflectionUtils.isObjectMethod(method)) {
return ReflectionUtils.invokeMethod(method, object, args);
}
@@ -634,11 +633,10 @@ public class ResolvableMethod {
@Override
@Nullable
public Object invoke(Object proxy, Method method, @Nullable Object[] args) {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return intercept(proxy, method, args, null);
}
@Nullable
Method getInvokedMethod() {
return this.invokedMethod;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -43,11 +43,12 @@ public interface ExchangeFunction {
/**
* Exchange the given request for a {@link ClientResponse} promise.
*
* <p><strong>Note:</strong> When calling this method from an
* {@link ExchangeFilterFunction} that handles the response in some way,
* extra care must be taken to always consume its content or otherwise
* propagate it downstream for further handling, for example by the
* {@link WebClient}. Please see the reference documentation for more
* {@link WebClient}. Please, see the reference documentation for more
* details on this.
* @param request the request to exchange
* @return the delayed response
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -109,9 +109,10 @@ public abstract class RequestPredicates {
*/
public static RequestPredicate path(String pattern) {
Assert.notNull(pattern, "'pattern' must not be null");
PathPatternParser parser = PathPatternParser.defaultInstance;
pattern = parser.initFullPathPattern(pattern);
return pathPredicates(parser).apply(pattern);
if (!pattern.isEmpty() && !pattern.startsWith("/")) {
pattern = "/" + pattern;
}
return pathPredicates(PathPatternParser.defaultInstance).apply(pattern);
}
/**
@@ -29,9 +29,9 @@ import org.springframework.beans.BeansException;
import org.springframework.http.server.PathContainer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;
/**
* Abstract base class for URL-mapped
@@ -211,9 +211,8 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
Object resolvedHandler = handler;
// Parse path pattern
PathPatternParser parser = getPathPatternParser();
urlPath = parser.initFullPathPattern(urlPath);
PathPattern pattern = parser.parse(urlPath);
urlPath = prependLeadingSlash(urlPath);
PathPattern pattern = getPathPatternParser().parse(urlPath);
if (this.handlerMap.containsKey(pattern)) {
Object existingHandler = this.handlerMap.get(pattern);
if (existingHandler != null && existingHandler != resolvedHandler) {
@@ -242,4 +241,14 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
return (handler instanceof String ? "'" + handler + "'" : handler.toString());
}
private static String prependLeadingSlash(String pattern) {
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
return "/" + pattern;
}
else {
return pattern;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -35,6 +35,7 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.http.server.PathContainer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPattern;
@@ -85,9 +86,8 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
public void registerHandlers(Map<String, ResourceWebHandler> handlerMap) {
this.handlerMap.clear();
handlerMap.forEach((rawPattern, resourceWebHandler) -> {
PathPatternParser parser = PathPatternParser.defaultInstance;
rawPattern = parser.initFullPathPattern(rawPattern);
PathPattern pattern = parser.parse(rawPattern);
rawPattern = prependLeadingSlash(rawPattern);
PathPattern pattern = PathPatternParser.defaultInstance.parse(rawPattern);
this.handlerMap.put(pattern, resourceWebHandler);
});
}
@@ -173,4 +173,14 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
});
}
private static String prependLeadingSlash(String pattern) {
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
return "/" + pattern;
}
else {
return pattern;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -602,9 +602,11 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
return Collections.emptyList();
}
List<PathPattern> result = new ArrayList<>(patterns.length);
for (String pattern : patterns) {
pattern = parser.initFullPathPattern(pattern);
result.add(parser.parse(pattern));
for (String path : patterns) {
if (StringUtils.hasText(path) && !path.startsWith("/")) {
path = "/" + path;
}
result.add(parser.parse(path));
}
return result;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2019 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -108,9 +108,10 @@ public abstract class RequestPredicates {
*/
public static RequestPredicate path(String pattern) {
Assert.notNull(pattern, "'pattern' must not be null");
PathPatternParser parser = PathPatternParser.defaultInstance;
pattern = parser.initFullPathPattern(pattern);
return pathPredicates(parser).apply(pattern);
if (!pattern.isEmpty() && !pattern.startsWith("/")) {
pattern = "/" + pattern;
}
return pathPredicates(PathPatternParser.defaultInstance).apply(pattern);
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2020 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.
@@ -51,7 +51,6 @@ import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.util.ServletRequestPathUtils;
import org.springframework.web.util.UrlPathHelper;
import org.springframework.web.util.pattern.PathPatternParser;
/**
* Helper class to get information from the {@code HandlerMapping} that would
@@ -328,15 +327,10 @@ public class HandlerMappingIntrospector
ServletRequestPathUtils.PATH_ATTRIBUTE : UrlPathHelper.PATH_ATTRIBUTE);
}
@Override
public PathPatternParser getPatternParser() {
return this.delegate.getPatternParser();
}
@Nullable
@Override
public RequestMatchResult match(HttpServletRequest request, String pattern) {
pattern = initFullPathPattern(pattern);
pattern = (StringUtils.hasLength(pattern) && !pattern.startsWith("/") ? "/" + pattern : pattern);
Object previousPath = request.getAttribute(this.pathAttributeName);
request.setAttribute(this.pathAttributeName, this.lookupPath);
try {
@@ -347,11 +341,6 @@ public class HandlerMappingIntrospector
}
}
private String initFullPathPattern(String pattern) {
PathPatternParser parser = (getPatternParser() != null ? getPatternParser() : PathPatternParser.defaultInstance);
return parser.initFullPathPattern(pattern);
}
@Nullable
@Override
public HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
@@ -75,9 +75,11 @@ public final class PathPatternsRequestCondition extends AbstractRequestCondition
return EMPTY_PATH_PATTERN;
}
SortedSet<PathPattern> result = new TreeSet<>();
for (String pattern : patterns) {
pattern = parser.initFullPathPattern(pattern);
result.add(parser.parse(pattern));
for (String path : patterns) {
if (StringUtils.hasText(path) && !path.startsWith("/")) {
path = "/" + path;
}
result.add(parser.parse(path));
}
return result;
}
@@ -35,7 +35,6 @@ import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UrlPathHelper;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;
/**
* A logical disjunction (' || ') request condition that matches a request
@@ -157,7 +156,9 @@ public class PatternsRequestCondition extends AbstractRequestCondition<PatternsR
}
Set<String> result = new LinkedHashSet<>(patterns.length);
for (String pattern : patterns) {
pattern = PathPatternParser.defaultInstance.initFullPathPattern(pattern);
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
pattern = "/" + pattern;
}
result.add(pattern);
}
return result;
@@ -65,7 +65,6 @@ import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.pattern.PathPatternParser;
/**
* Creates instances of {@link org.springframework.web.util.UriComponentsBuilder}
@@ -545,7 +544,9 @@ public class MvcUriComponentsBuilder {
String typePath = getClassMapping(controllerType);
String methodPath = getMethodMapping(method);
String path = pathMatcher.combine(typePath, methodPath);
path = PathPatternParser.defaultInstance.initFullPathPattern(path);
if (StringUtils.hasLength(path) && !path.startsWith("/")) {
path = "/" + path;
}
builder.path(path);
return applyContributors(builder, method, args);
@@ -741,8 +742,8 @@ public class MvcUriComponentsBuilder {
@Override
@Nullable
public Object invoke(Object proxy, Method method, @Nullable Object[] args) {
return intercept(proxy, method, (args != null ? args : new Object[0]), null);
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return intercept(proxy, method, args, null);
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 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.
@@ -287,14 +287,6 @@ public class MvcUriComponentsBuilderTests {
assertThat(uriComponents.toUriString()).isEqualTo("http://localhost/input");
}
@Test
public void fromMethodCallOnSubclass() {
UriComponents uriComponents = fromMethodCall(on(ExtendedController.class).myMethod(null)).build();
assertThat(uriComponents.toUriString()).startsWith("http://localhost");
assertThat(uriComponents.toUriString()).endsWith("/extended/else");
}
@Test
public void fromMethodCallPlain() {
UriComponents uriComponents = fromMethodCall(on(ControllerWithMethods.class).myMethod(null)).build();
@@ -304,27 +296,11 @@ public class MvcUriComponentsBuilderTests {
}
@Test
public void fromMethodCallPlainWithNoArguments() {
UriComponents uriComponents = fromMethodCall(on(ControllerWithMethods.class).myMethod()).build();
public void fromMethodCallOnSubclass() {
UriComponents uriComponents = fromMethodCall(on(ExtendedController.class).myMethod(null)).build();
assertThat(uriComponents.toUriString()).startsWith("http://localhost");
assertThat(uriComponents.toUriString()).endsWith("/something/noarg");
}
@Test
public void fromMethodCallPlainOnInterface() {
UriComponents uriComponents = fromMethodCall(on(ControllerInterface.class).myMethod(null)).build();
assertThat(uriComponents.toUriString()).startsWith("http://localhost");
assertThat(uriComponents.toUriString()).endsWith("/something/else");
}
@Test
public void fromMethodCallPlainWithNoArgumentsOnInterface() {
UriComponents uriComponents = fromMethodCall(on(ControllerInterface.class).myMethod()).build();
assertThat(uriComponents.toUriString()).startsWith("http://localhost");
assertThat(uriComponents.toUriString()).endsWith("/something/noarg");
assertThat(uriComponents.toUriString()).endsWith("/extended/else");
}
@Test
@@ -577,11 +553,6 @@ public class MvcUriComponentsBuilderTests {
return null;
}
@RequestMapping("/noarg")
HttpEntity<Void> myMethod() {
return null;
}
@RequestMapping("/{id}/foo")
HttpEntity<Void> methodWithPathVariable(@PathVariable String id) {
return null;
@@ -623,17 +594,6 @@ public class MvcUriComponentsBuilderTests {
}
@RequestMapping("/something")
public interface ControllerInterface {
@RequestMapping("/else")
HttpEntity<Void> myMethod(@RequestBody Object payload);
@RequestMapping("/noarg")
HttpEntity<Void> myMethod();
}
@RequestMapping("/user/{userId}/contacts")
static class UserContactController {
+66 -83
View File
@@ -1455,6 +1455,7 @@ In XML configuration, the `<tx:annotation-driven/>` tag provides similar conveni
----
<1> The line that makes the bean instance transactional.
TIP: You can omit the `transaction-manager` attribute in the `<tx:annotation-driven/>`
tag if the bean name of the `TransactionManager` that you want to wire in has the name
`transactionManager`. If the `TransactionManager` bean that you want to dependency-inject
@@ -1834,17 +1835,17 @@ The following listing shows the bean declarations:
----
<tx:annotation-driven/>
<bean id="transactionManager1" class="org.springframework.jdbc.support.JdbcTransactionManager">
<bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
...
<qualifier value="order"/>
</bean>
<bean id="transactionManager2" class="org.springframework.jdbc.support.JdbcTransactionManager">
<bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
...
<qualifier value="account"/>
</bean>
<bean id="transactionManager3" class="org.springframework.data.r2dbc.connection.R2dbcTransactionManager">
<bean id="transactionManager3" class="org.springframework.data.r2dbc.connectionfactory.R2dbcTransactionManager">
...
<qualifier value="reactive-account"/>
</bean>
@@ -3023,10 +3024,10 @@ example shows:
}
----
The last example we show here is for typical JDBC support. You could have the `DataSource`
injected into an initialization method or a constructor, where you would create a `JdbcTemplate`
and other data access support classes (such as `SimpleJdbcCall` and others) by using this
`DataSource`. The following example autowires a `DataSource`:
The last example we show here is for typical JDBC support. You could have the
`DataSource` injected into an initialization method or a constructor, where you would create a
`JdbcTemplate` and other data access support classes (such as `SimpleJdbcCall` and others) by using
this `DataSource`. The following example autowires a `DataSource`:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
@@ -3156,30 +3157,30 @@ advanced features require a JDBC 3.0 driver.
The Spring Framework's JDBC abstraction framework consists of four different packages:
* `core`: The `org.springframework.jdbc.core` package contains the `JdbcTemplate` class
and its various callback interfaces, plus a variety of related classes. A subpackage
named `org.springframework.jdbc.core.simple` contains the `SimpleJdbcInsert` and
* `core`: The `org.springframework.jdbc.core` package contains the `JdbcTemplate` class and its
various callback interfaces, plus a variety of related classes. A subpackage named
`org.springframework.jdbc.core.simple` contains the `SimpleJdbcInsert` and
`SimpleJdbcCall` classes. Another subpackage named
`org.springframework.jdbc.core.namedparam` contains the `NamedParameterJdbcTemplate`
class and the related support classes. See <<jdbc-core>>, <<jdbc-advanced-jdbc>>, and
<<jdbc-simple-jdbc>>.
* `datasource`: The `org.springframework.jdbc.datasource` package contains a utility class
for easy `DataSource` access and various simple `DataSource` implementations that you can
use for testing and running unmodified JDBC code outside of a Java EE container. A subpackage
named `org.springframework.jdbc.datasource.embedded` provides support for creating
* `datasource`: The `org.springframework.jdbc.datasource` package contains a utility class for easy
`DataSource` access and various simple `DataSource` implementations that you can use for
testing and running unmodified JDBC code outside of a Java EE container. A subpackage
named `org.springfamework.jdbc.datasource.embedded` provides support for creating
embedded databases by using Java database engines, such as HSQL, H2, and Derby. See
<<jdbc-connections>> and <<jdbc-embedded-database-support>>.
* `object`: The `org.springframework.jdbc.object` package contains classes that represent
RDBMS queries, updates, and stored procedures as thread-safe, reusable objects. See
* `object`: The `org.springframework.jdbc.object` package contains classes that represent RDBMS
queries, updates, and stored procedures as thread-safe, reusable objects. See
<<jdbc-object>>. This approach is modeled by JDO, although objects returned by queries
are naturally disconnected from the database. This higher-level of JDBC abstraction
depends on the lower-level abstraction in the `org.springframework.jdbc.core` package.
* `support`: The `org.springframework.jdbc.support` package provides `SQLException`
translation functionality and some utility classes. Exceptions thrown during JDBC processing
are translated to exceptions defined in the `org.springframework.dao` package. This means
* `support`: The `org.springframework.jdbc.support` package provides `SQLException` translation
functionality and some utility classes. Exceptions thrown during JDBC processing are
translated to exceptions defined in the `org.springframework.dao` package. This means
that code using the Spring JDBC abstraction layer does not need to implement JDBC or
RDBMS-specific error handling. All translated exceptions are unchecked, which gives you
the option of catching the exceptions from which you can recover while letting other
@@ -3803,9 +3804,7 @@ See also <<jdbc-JdbcTemplate-idioms>> for guidelines on using the
between ``SQLException``s and Spring's own `org.springframework.dao.DataAccessException`,
which is agnostic in regard to data access strategy. Implementations can be generic (for
example, using SQLState codes for JDBC) or proprietary (for example, using Oracle error
codes) for greater precision. This exception translation mechanism is used behind the
the common `JdbcTemplate` and `JdbcTransactionManager` entry points which do not
propagate `SQLException` but rather `DataAccessException`.
codes) for greater precision.
`SQLErrorCodeSQLExceptionTranslator` is the implementation of `SQLExceptionTranslator`
that is used by default. This implementation uses specific vendor codes. It is more
@@ -3831,8 +3830,8 @@ The `SQLErrorCodeSQLExceptionTranslator` applies matching rules in the following
translator. If this translation is not available, the next fallback translator is
the `SQLStateSQLExceptionTranslator`.
NOTE: The `SQLErrorCodesFactory` is used by default to define error codes and custom
exception translations. They are looked up in a file named `sql-error-codes.xml` from the
NOTE: The `SQLErrorCodesFactory` is used by default to define `Error` codes and custom exception
translations. They are looked up in a file named `sql-error-codes.xml` from the
classpath, and the matching `SQLErrorCodes` instance is located based on the database
name from the database metadata of the database in use.
@@ -3865,12 +3864,12 @@ You can extend `SQLErrorCodeSQLExceptionTranslator`, as the following example sh
}
----
In the preceding example, the specific error code (`-12345`) is translated while
other errors are left to be translated by the default translator implementation.
To use this custom translator, you must pass it to the `JdbcTemplate` through the
method `setExceptionTranslator`, and you must use this `JdbcTemplate` for all of the
data access processing where this translator is needed. The following example shows
how you can use this custom translator:
In the preceding example, the specific error code (`-12345`) is translated, while other errors are
left to be translated by the default translator implementation. To use this custom
translator, you must pass it to the `JdbcTemplate` through the method
`setExceptionTranslator`, and you must use this `JdbcTemplate` for all of the data access
processing where this translator is needed. The following example shows how you can use this custom
translator:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
@@ -3878,6 +3877,7 @@ how you can use this custom translator:
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
// create a JdbcTemplate and set data source
this.jdbcTemplate = new JdbcTemplate();
this.jdbcTemplate.setDataSource(dataSource);
@@ -3886,6 +3886,7 @@ how you can use this custom translator:
CustomSQLErrorCodesTranslator tr = new CustomSQLErrorCodesTranslator();
tr.setDataSource(dataSource);
this.jdbcTemplate.setExceptionTranslator(tr);
}
public void updateShippingCharge(long orderId, long pct) {
@@ -4259,12 +4260,8 @@ The following example shows C3P0 configuration:
==== Using `DataSourceUtils`
The `DataSourceUtils` class is a convenient and powerful helper class that provides
`static` methods to obtain connections from JNDI and close connections if necessary.
It supports a thread-bound JDBC `Connection` with `DataSourceTransactionManager` but
also with `JtaTransactionManager` and `JpaTransactionManager`.
Note that `JdbcTemplate` implies `DataSourceUtils` connection access, using it
behind every JDBC operation, implicitly participating in an ongoing transaction.
`static` methods to obtain connections from JNDI and close connections if necessary. It
supports thread-bound connections with, for example, `DataSourceTransactionManager`.
[[jdbc-SmartDataSource]]
@@ -4303,6 +4300,7 @@ In contrast to `DriverManagerDataSource`, it reuses the same connection all the
avoiding excessive creation of physical connections.
[[jdbc-DriverManagerDataSource]]
==== Using `DriverManagerDataSource`
@@ -4338,47 +4336,29 @@ javadoc for more details.
[[jdbc-DataSourceTransactionManager]]
==== Using `DataSourceTransactionManager` / `JdbcTransactionManager`
==== Using `DataSourceTransactionManager`
The `DataSourceTransactionManager` class is a `PlatformTransactionManager`
implementation for a single JDBC `DataSource`. It binds a JDBC `Connection`
from the specified `DataSource` to the currently executing thread, potentially
allowing for one thread-bound `Connection` per `DataSource`.
implementation for single JDBC datasources. It binds a JDBC connection from the
specified data source to the currently executing thread, potentially allowing for one
thread connection per data source.
Application code is required to retrieve the JDBC `Connection` through
Application code is required to retrieve the JDBC connection through
`DataSourceUtils.getConnection(DataSource)` instead of Java EE's standard
`DataSource.getConnection`. It throws unchecked `org.springframework.dao` exceptions
instead of checked `SQLExceptions`. All framework classes (such as `JdbcTemplate`) use
this strategy implicitly. If not used with a transaction manager, the lookup strategy
behaves exactly like `DataSource.getConnection` and can therefore be used in any case.
instead of checked `SQLExceptions`. All framework classes (such as `JdbcTemplate`) use this
strategy implicitly. If not used with this transaction manager, the lookup strategy
behaves exactly like the common one. Thus, it can be used in any case.
The `DataSourceTransactionManager` class supports savepoints (`PROPAGATION_NESTED`),
custom isolation levels, and timeouts that get applied as appropriate JDBC statement
query timeouts. To support the latter, application code must either use `JdbcTemplate` or
call the `DataSourceUtils.applyTransactionTimeout(..)` method for each created statement.
The `DataSourceTransactionManager` class supports custom isolation levels and timeouts
that get applied as appropriate JDBC statement query timeouts. To support the latter,
application code must either use `JdbcTemplate` or call the
`DataSourceUtils.applyTransactionTimeout(..)` method for each created statement.
You can use `DataSourceTransactionManager` instead of `JtaTransactionManager` in the
single-resource case, as it does not require the container to support a JTA transaction
coordinator. Switching between these transaction managers is just a matter of configuration,
provided you stick to the required connection lookup pattern. Note that JTA does not support
savepoints or custom isolation levels and has a different timeout mechanism but otherwise
exposes similar behavior in terms of JDBC resources and JDBC commit/rollback management.
[NOTE]
====
As of 5.3, Spring provides an extended `JdbcTransactionManager` variant which adds
exception translation capabilities on commit/rollback (aligned with `JdbcTemplate`).
Where `DataSourceTransactionManager` will only ever throw `TransactionSystemException`
(analogous to JTA), `JdbcTransactionManager` translates database locking failures etc to
corresponding `DataAccessException` subclasses. Note that application code needs to be
prepared for such exceptions, not exclusively expecting `TransactionSystemException`.
In scenarios where that is the case, `JdbcTransactionManager` is the recommended choice.
In terms of exception behavior, `JdbcTransactionManager` is roughly equivalent to
`JpaTransactionManager` and also to `R2dbcTransactionManager`, serving as an immediate
companion/replacement for each other. `DataSourceTransactionManager` on the other hand
is equivalent to `JtaTransactionManager` and can serve as a direct replacement there.
====
You can use this implementation instead of `JtaTransactionManager` in the single-resource
case, as it does not require the container to support JTA. Switching between
both is just a matter of configuration, provided you stick to the required connection lookup
pattern. JTA does not support custom isolation levels.
@@ -4393,13 +4373,13 @@ to the database.
[[jdbc-batch-classic]]
==== Basic Batch Operations with `JdbcTemplate`
You accomplish `JdbcTemplate` batch processing by implementing two methods of a special interface,
`BatchPreparedStatementSetter`, and passing that implementation in as the second parameter
You accomplish `JdbcTemplate` batch processing by implementing two methods of a special
interface, `BatchPreparedStatementSetter`, and passing that implementation in as the second parameter
in your `batchUpdate` method call. You can use the `getBatchSize` method to provide the size of
the current batch. You can use the `setValues` method to set the values for the parameters of
the prepared statement. This method is called the number of times that you specified in the
`getBatchSize` call. The following example updates the `t_actor` table based on entries in a list,
and the entire list is used as the batch:
the prepared statement. This method is called the number of times that you
specified in the `getBatchSize` call. The following example updates the `t_actor` table
based on entries in a list, and the entire list is used as the batch:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
@@ -7296,16 +7276,19 @@ javadoc for more details.
==== Using `R2dbcTransactionManager`
The `R2dbcTransactionManager` class is a `ReactiveTransactionManager` implementation for
a single R2DBC `ConnectionFactory`. It binds an R2DBC `Connection` from the specified
`ConnectionFactory` to the subscriber `Context`, potentially allowing for one subscriber
`Connection` for each `ConnectionFactory`.
single R2DBC datasources. It binds an R2DBC connection from the specified connection factory
to the subscriber `Context`, potentially allowing for one subscriber connection for each
connection factory.
Application code is required to retrieve the R2DBC `Connection` through
Application code is required to retrieve the R2DBC connection through
`ConnectionFactoryUtils.getConnection(ConnectionFactory)`, instead of R2DBC's standard
`ConnectionFactory.create()`. All framework classes (such as `DatabaseClient`) use this
strategy implicitly. If not used with a transaction manager, the lookup strategy behaves
exactly like `ConnectionFactory.create()` and can therefore be used in any case.
`ConnectionFactory.create()`.
All framework classes (such as `DatabaseClient`) use this strategy implicitly.
If not used with this transaction manager, the lookup strategy behaves exactly like the common one.
Thus, it can be used in any case.
The `R2dbcTransactionManager` class supports custom isolation levels that get applied to the connection.
@@ -8474,7 +8457,7 @@ features supported by Spring, usually in a vendor-specific manner:
* Applying specific transaction semantics (such as custom isolation level or transaction
timeout)
* Retrieving the transactional JDBC `Connection` (for exposure to JDBC-based DAOs)
* Advanced translation of `PersistenceException` to Spring's `DataAccessException`
* Advanced translation of `PersistenceExceptions` to Spring `DataAccessExceptions`
This is particularly valuable for special transaction semantics and for advanced
translation of exception. The default implementation (`DefaultJpaDialect`) does