mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 13b31c7976 | |||
| 53319381d0 | |||
| e1e7fa489b | |||
| e1351a5cb5 | |||
| ac94d2bd54 | |||
| 16fd70ae35 | |||
| c1bf09952b | |||
| 9e7ee0cb8e | |||
| 1cd994d3a8 | |||
| 3d28c024c5 | |||
| 3444892aea | |||
| 14a7983eef | |||
| 0a4f290f0f | |||
| 6ea4d3794a | |||
| 85eec5d344 | |||
| 0961bc546a | |||
| f2df10c7fe | |||
| 03f1fabbdb | |||
| 2ada2b77f6 | |||
| d5380b3070 | |||
| a3907a64e5 | |||
| dd16e012ba | |||
| d4cd358c76 | |||
| da814e01c7 | |||
| 5d4c2846d9 | |||
| a3daee6ad8 | |||
| 5614e5bc18 | |||
| 6dde13f597 | |||
| c057da23ec | |||
| a7f07328ab | |||
| 45f747fae1 | |||
| 258bd3f73c | |||
| 97b95d9d01 | |||
| 69827a2f21 | |||
| ef699b6a9e | |||
| e440eb8365 | |||
| 02cbee560d | |||
| 14da1aca2f | |||
| ce97342fee | |||
| 2e51aa250e | |||
| ec2957afc8 | |||
| d3df45d8fe | |||
| 5375f62dc1 | |||
| c7bc40d3ba | |||
| 1071778aa9 | |||
| 40a9ae9d14 | |||
| e34a7baeb3 | |||
| 62eb9b391d | |||
| ea89bf2c91 |
+6
-6
@@ -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.93.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:2020.0.33"
|
||||
mavenBom "io.netty:netty-bom:4.1.94.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:2020.0.34"
|
||||
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.75') {
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.78') {
|
||||
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.75') {
|
||||
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.78') {
|
||||
entry 'tomcat-embed-core'
|
||||
entry 'tomcat-embed-websocket'
|
||||
}
|
||||
dependencySet(group: 'io.undertow', version: '2.2.24.Final') {
|
||||
dependencySet(group: 'io.undertow', version: '2.2.25.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.9.3"
|
||||
toolVersion = "10.12.1"
|
||||
configDirectory.set(rootProject.file("src/checkstyle"))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ubuntu:focal-20220922
|
||||
FROM ubuntu:jammy-20230624
|
||||
|
||||
ADD setup.sh /setup.sh
|
||||
ADD get-jdk-url.sh /get-jdk-url.sh
|
||||
|
||||
@@ -5,6 +5,8 @@ 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
|
||||
|
||||
@@ -5,6 +5,8 @@ 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
@@ -1,4 +1,4 @@
|
||||
version=5.3.28
|
||||
version=5.3.29
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
org.gradle.caching=true
|
||||
org.gradle.parallel=true
|
||||
|
||||
+23
-16
@@ -594,7 +594,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
* Resolve the specified cached method argument or field value.
|
||||
*/
|
||||
@Nullable
|
||||
private Object resolvedCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) {
|
||||
private Object resolveCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) {
|
||||
if (cachedArgument instanceof DependencyDescriptor) {
|
||||
DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument;
|
||||
Assert.state(this.beanFactory != null, "No BeanFactory available");
|
||||
@@ -629,10 +629,12 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
Object value;
|
||||
if (this.cached) {
|
||||
try {
|
||||
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
|
||||
value = resolveCachedArgument(beanName, this.cachedFieldValue);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// Unexpected removal of target bean for cached argument -> re-resolve
|
||||
catch (BeansException ex) {
|
||||
// Unexpected target bean mismatch for cached argument -> re-resolve
|
||||
this.cached = false;
|
||||
logger.debug("Failed to resolve cached argument", ex);
|
||||
value = resolveFieldValue(field, bean, beanName);
|
||||
}
|
||||
}
|
||||
@@ -661,9 +663,8 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
Object cachedFieldValue = null;
|
||||
if (value != null || this.required) {
|
||||
cachedFieldValue = desc;
|
||||
Object cachedFieldValue = desc;
|
||||
registerDependentBeans(beanName, autowiredBeanNames);
|
||||
if (value != null && autowiredBeanNames.size() == 1) {
|
||||
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
||||
@@ -673,9 +674,13 @@ 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;
|
||||
@@ -709,10 +714,12 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
Object[] arguments;
|
||||
if (this.cached) {
|
||||
try {
|
||||
arguments = resolveCachedArguments(beanName);
|
||||
arguments = resolveCachedArguments(beanName, this.cachedMethodArguments);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// Unexpected removal of target bean for cached argument -> re-resolve
|
||||
catch (BeansException ex) {
|
||||
// Unexpected target bean mismatch for cached argument -> re-resolve
|
||||
this.cached = false;
|
||||
logger.debug("Failed to resolve cached argument", ex);
|
||||
arguments = resolveMethodArguments(method, bean, beanName);
|
||||
}
|
||||
}
|
||||
@@ -731,14 +738,13 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object[] resolveCachedArguments(@Nullable String beanName) {
|
||||
Object[] cachedMethodArguments = this.cachedMethodArguments;
|
||||
private Object[] resolveCachedArguments(@Nullable String beanName, @Nullable Object[] cachedMethodArguments) {
|
||||
if (cachedMethodArguments == null) {
|
||||
return null;
|
||||
}
|
||||
Object[] arguments = new Object[cachedMethodArguments.length];
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
arguments[i] = resolvedCachedArgument(beanName, cachedMethodArguments[i]);
|
||||
arguments[i] = resolveCachedArgument(beanName, cachedMethodArguments[i]);
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
@@ -771,7 +777,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
if (arguments != null) {
|
||||
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
|
||||
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, argumentCount);
|
||||
registerDependentBeans(beanName, autowiredBeans);
|
||||
if (autowiredBeans.size() == argumentCount) {
|
||||
Iterator<String> it = autowiredBeans.iterator();
|
||||
@@ -786,11 +792,12 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
}
|
||||
}
|
||||
this.cachedMethodArguments = cachedMethodArguments;
|
||||
this.cached = true;
|
||||
}
|
||||
else {
|
||||
this.cachedMethodArguments = null;
|
||||
// cached flag remains false
|
||||
}
|
||||
this.cached = true;
|
||||
}
|
||||
}
|
||||
return arguments;
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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 = this.getApplicationStartup().start("spring.beans.smart-initialize")
|
||||
StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
|
||||
.tag("beanName", beanName);
|
||||
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
|
||||
if (System.getSecurityManager() != null) {
|
||||
|
||||
+5
-5
@@ -447,17 +447,17 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
}
|
||||
String canonicalName = canonicalName(beanName);
|
||||
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
|
||||
if (dependentBeans == null) {
|
||||
if (dependentBeans == null || dependentBeans.isEmpty()) {
|
||||
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;
|
||||
}
|
||||
|
||||
+16
-23
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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,23 +506,12 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
if (isExternallyManagedInitMethod(initMethod)) {
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
return hasAnyExternallyManagedMethod(this.externallyManagedInitMethods, initMethod);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all externally managed initialization methods (as an immutable Set).
|
||||
* Get 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
|
||||
@@ -583,19 +572,23 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
if (isExternallyManagedDestroyMethod(destroyMethod)) {
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+195
-122
@@ -124,11 +124,11 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
|
||||
ResourceInjectionBean bean = (ResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
ResourceInjectionBean bean = bf.getBean("annotatedBean", ResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
|
||||
bean = (ResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", ResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
}
|
||||
@@ -142,12 +142,66 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
tb.setFactoryMethodName("createTestBean");
|
||||
bf.registerBeanDefinition("testBean", tb);
|
||||
|
||||
NonPublicResourceInjectionBean bean = (NonPublicResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
@SuppressWarnings("rawtypes")
|
||||
NonPublicResourceInjectionBean bean = bf.getBean("annotatedBean", NonPublicResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
|
||||
bean = (NonPublicResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
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");
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
@@ -163,7 +217,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
NestedTestBean ntb = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
TypedExtendedResourceInjectionBean bean = (TypedExtendedResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
TypedExtendedResourceInjectionBean bean = bf.getBean("annotatedBean", TypedExtendedResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -171,7 +225,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
assertThat(bean.getNestedTestBean()).isSameAs(ntb);
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bean = (TypedExtendedResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", TypedExtendedResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -193,7 +247,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
TestBean tb = bf.getBean("testBean", TestBean.class);
|
||||
TypedExtendedResourceInjectionBean bean = (TypedExtendedResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
TypedExtendedResourceInjectionBean bean = bf.getBean("annotatedBean", TypedExtendedResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -220,7 +274,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
NestedTestBean ntb = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
TypedExtendedResourceInjectionBean bean = (TypedExtendedResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
TypedExtendedResourceInjectionBean bean = bf.getBean("annotatedBean", TypedExtendedResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb2);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -238,7 +292,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
NestedTestBean ntb = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
OverriddenExtendedResourceInjectionBean bean = (OverriddenExtendedResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
OverriddenExtendedResourceInjectionBean bean = bf.getBean("annotatedBean", OverriddenExtendedResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -258,7 +312,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
NestedTestBean ntb = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
DefaultMethodResourceInjectionBean bean = (DefaultMethodResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
DefaultMethodResourceInjectionBean bean = bf.getBean("annotatedBean", DefaultMethodResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -281,7 +335,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
NestedTestBean ntb = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
TypedExtendedResourceInjectionBean bean = (TypedExtendedResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
TypedExtendedResourceInjectionBean bean = bf.getBean("annotatedBean", TypedExtendedResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -302,7 +356,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
NestedTestBean ntb2 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
OptionalResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -330,7 +384,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
NestedTestBean ntb2 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
OptionalResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -345,7 +399,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
bf.destroySingleton("testBean");
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
@@ -360,7 +414,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
bf.registerSingleton("testBean", tb);
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -387,7 +441,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
NestedTestBean ntb2 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
OptionalResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean2()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean3()).isSameAs(bf.getBean("testBean"));
|
||||
@@ -402,7 +456,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
bf.removeBeanDefinition("testBean");
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
@@ -417,7 +471,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean2()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean3()).isSameAs(bf.getBean("testBean"));
|
||||
@@ -446,8 +500,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
// Two calls to verify that caching doesn't break re-creation.
|
||||
OptionalCollectionResourceInjectionBean bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
OptionalCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
|
||||
bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -477,8 +531,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerSingleton("nestedTestBean1", ntb1);
|
||||
|
||||
// Two calls to verify that caching doesn't break re-creation.
|
||||
OptionalCollectionResourceInjectionBean bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
OptionalCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
|
||||
bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -498,7 +552,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
|
||||
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
OptionalResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -510,7 +564,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
public void testOptionalResourceInjectionWithNoDependencies() {
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalResourceInjectionBean.class));
|
||||
|
||||
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
OptionalResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
@@ -532,7 +586,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
ntb2.setOrder(1);
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
OptionalResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -558,7 +612,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
FixedOrder1NestedTestBean ntb2 = new FixedOrder1NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
OptionalResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -589,8 +643,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
// Two calls to verify that caching doesn't break re-creation.
|
||||
OptionalCollectionResourceInjectionBean bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
OptionalCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
|
||||
bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -622,8 +676,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
// Two calls to verify that caching doesn't break re-creation.
|
||||
OptionalCollectionResourceInjectionBean bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = (OptionalCollectionResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
OptionalCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
|
||||
bean = bf.getBean("annotatedBean", OptionalCollectionResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -650,7 +704,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
NestedTestBean ntb = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
ConstructorResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -658,7 +712,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
assertThat(bean.getNestedTestBean()).isSameAs(ntb);
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -677,7 +731,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
NestedTestBean ntb = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
ConstructorResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -687,7 +741,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
bf.destroySingleton("nestedTestBean");
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -697,7 +751,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -715,7 +769,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerSingleton("testBean", tb);
|
||||
bf.registerBeanDefinition("nestedTestBean", new RootBeanDefinition(NestedTestBean.class));
|
||||
|
||||
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
ConstructorResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -725,7 +779,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
bf.removeBeanDefinition("nestedTestBean");
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -735,7 +789,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
bf.registerBeanDefinition("nestedTestBean", new RootBeanDefinition(NestedTestBean.class));
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -754,7 +808,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("nestedTestBean", new RootBeanDefinition(NullNestedTestBeanFactoryBean.class));
|
||||
bf.registerSingleton("nestedTestBean2", new NestedTestBean());
|
||||
|
||||
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
ConstructorResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -762,7 +816,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
assertThat(bean.getNestedTestBean()).isNull();
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
@@ -784,7 +838,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("nestedTestBean", ntb);
|
||||
bf.registerSingleton("nestedTestBean2", new NestedTestBean());
|
||||
|
||||
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
ConstructorResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
@@ -792,7 +846,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
assertThat(bean.getNestedTestBean()).isNull();
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", ConstructorResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
@@ -811,7 +865,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
NestedTestBean ntb2 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
ConstructorsResourceInjectionBean bean = (ConstructorsResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
ConstructorsResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
@@ -822,8 +876,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));
|
||||
}
|
||||
|
||||
@@ -837,7 +891,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
NestedTestBean ntb2 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
ConstructorsCollectionResourceInjectionBean bean = (ConstructorsCollectionResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
ConstructorsCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsCollectionResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBeans().size()).isEqualTo(1);
|
||||
@@ -859,7 +913,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
NestedTestBean ntb2 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
ConstructorsCollectionResourceInjectionBean bean = (ConstructorsCollectionResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
ConstructorsCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsCollectionResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBeans().size()).isEqualTo(2);
|
||||
@@ -877,7 +931,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
FixedOrder1NestedTestBean ntb2 = new FixedOrder1NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
ConstructorsResourceInjectionBean bean = (ConstructorsResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
ConstructorsResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
@@ -895,7 +949,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
FixedOrder1NestedTestBean ntb2 = new FixedOrder1NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
ConstructorsCollectionResourceInjectionBean bean = (ConstructorsCollectionResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
ConstructorsCollectionResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsCollectionResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBeans().size()).isEqualTo(2);
|
||||
@@ -913,7 +967,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
FixedOrder1NestedTestBean ntb2 = new FixedOrder1NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
SingleConstructorVarargBean bean = (SingleConstructorVarargBean) bf.getBean("annotatedBean");
|
||||
SingleConstructorVarargBean bean = bf.getBean("annotatedBean", SingleConstructorVarargBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBeans().size()).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans().get(0)).isSameAs(ntb2);
|
||||
@@ -926,7 +980,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
|
||||
SingleConstructorVarargBean bean = (SingleConstructorVarargBean) bf.getBean("annotatedBean");
|
||||
SingleConstructorVarargBean bean = bf.getBean("annotatedBean", SingleConstructorVarargBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBeans()).isNotNull();
|
||||
assertThat(bean.getNestedTestBeans().isEmpty()).isTrue();
|
||||
@@ -942,7 +996,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
FixedOrder1NestedTestBean ntb2 = new FixedOrder1NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
SingleConstructorRequiredCollectionBean bean = (SingleConstructorRequiredCollectionBean) bf.getBean("annotatedBean");
|
||||
SingleConstructorRequiredCollectionBean bean = bf.getBean("annotatedBean", SingleConstructorRequiredCollectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBeans().size()).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans().get(0)).isSameAs(ntb2);
|
||||
@@ -955,7 +1009,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
|
||||
SingleConstructorRequiredCollectionBean bean = (SingleConstructorRequiredCollectionBean) bf.getBean("annotatedBean");
|
||||
SingleConstructorRequiredCollectionBean bean = bf.getBean("annotatedBean", SingleConstructorRequiredCollectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBeans()).isNotNull();
|
||||
assertThat(bean.getNestedTestBeans().isEmpty()).isTrue();
|
||||
@@ -971,7 +1025,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
FixedOrder1NestedTestBean ntb2 = new FixedOrder1NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
SingleConstructorOptionalCollectionBean bean = (SingleConstructorOptionalCollectionBean) bf.getBean("annotatedBean");
|
||||
SingleConstructorOptionalCollectionBean bean = bf.getBean("annotatedBean", SingleConstructorOptionalCollectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBeans().size()).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans().get(0)).isSameAs(ntb2);
|
||||
@@ -984,7 +1038,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
|
||||
SingleConstructorOptionalCollectionBean bean = (SingleConstructorOptionalCollectionBean) bf.getBean("annotatedBean");
|
||||
SingleConstructorOptionalCollectionBean bean = bf.getBean("annotatedBean", SingleConstructorOptionalCollectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBeans()).isNull();
|
||||
}
|
||||
@@ -992,8 +1046,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
|
||||
@@ -1002,8 +1056,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
|
||||
@@ -1012,7 +1066,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
|
||||
ConstructorsResourceInjectionBean bean = (ConstructorsResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
ConstructorsResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isNull();
|
||||
}
|
||||
@@ -1021,7 +1075,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
public void testConstructorResourceInjectionWithMultipleCandidatesAndDefaultFallback() {
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ConstructorsResourceInjectionBean.class));
|
||||
|
||||
ConstructorsResourceInjectionBean bean = (ConstructorsResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
ConstructorsResourceInjectionBean bean = bf.getBean("annotatedBean", ConstructorsResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
assertThat(bean.getTestBean4()).isNull();
|
||||
}
|
||||
@@ -1037,12 +1091,12 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
tb2.setFactoryMethodName("createTestBean");
|
||||
bf.registerBeanDefinition("testBean2", tb2);
|
||||
|
||||
MapConstructorInjectionBean bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
MapConstructorInjectionBean bean = bf.getBean("annotatedBean", MapConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanMap().size()).isEqualTo(1);
|
||||
assertThat(bean.getTestBeanMap().get("testBean1")).isSameAs(tb1);
|
||||
assertThat(bean.getTestBeanMap().get("testBean2")).isNull();
|
||||
|
||||
bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", MapConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanMap().size()).isEqualTo(1);
|
||||
assertThat(bean.getTestBeanMap().get("testBean1")).isSameAs(tb1);
|
||||
assertThat(bean.getTestBeanMap().get("testBean2")).isNull();
|
||||
@@ -1058,14 +1112,14 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerSingleton("testBean1", tb1);
|
||||
bf.registerSingleton("testBean2", tb2);
|
||||
|
||||
MapFieldInjectionBean bean = (MapFieldInjectionBean) bf.getBean("annotatedBean");
|
||||
MapFieldInjectionBean bean = bf.getBean("annotatedBean", MapFieldInjectionBean.class);
|
||||
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 = (MapFieldInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", MapFieldInjectionBean.class);
|
||||
assertThat(bean.getTestBeanMap().size()).isEqualTo(2);
|
||||
assertThat(bean.getTestBeanMap().keySet().contains("testBean1")).isTrue();
|
||||
assertThat(bean.getTestBeanMap().keySet().contains("testBean2")).isTrue();
|
||||
@@ -1081,13 +1135,13 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
|
||||
MapMethodInjectionBean bean = (MapMethodInjectionBean) bf.getBean("annotatedBean");
|
||||
MapMethodInjectionBean bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
|
||||
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 = (MapMethodInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
|
||||
assertThat(bean.getTestBeanMap().size()).isEqualTo(1);
|
||||
assertThat(bean.getTestBeanMap().keySet().contains("testBean")).isTrue();
|
||||
assertThat(bean.getTestBeanMap().values().contains(tb)).isTrue();
|
||||
@@ -1099,9 +1153,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
|
||||
@@ -1112,8 +1166,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
rbd2.setAutowireCandidate(false);
|
||||
bf.registerBeanDefinition("testBean2", rbd2);
|
||||
|
||||
MapMethodInjectionBean bean = (MapMethodInjectionBean) bf.getBean("annotatedBean");
|
||||
TestBean tb = (TestBean) bf.getBean("testBean1");
|
||||
MapMethodInjectionBean bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
|
||||
TestBean tb = bf.getBean("testBean1", TestBean.class);
|
||||
assertThat(bean.getTestBeanMap().size()).isEqualTo(1);
|
||||
assertThat(bean.getTestBeanMap().keySet().contains("testBean1")).isTrue();
|
||||
assertThat(bean.getTestBeanMap().values().contains(tb)).isTrue();
|
||||
@@ -1124,7 +1178,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
public void testMethodInjectionWithMapAndNoMatches() {
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class));
|
||||
|
||||
MapMethodInjectionBean bean = (MapMethodInjectionBean) bf.getBean("annotatedBean");
|
||||
MapMethodInjectionBean bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
|
||||
assertThat(bean.getTestBeanMap()).isNull();
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
}
|
||||
@@ -1140,9 +1194,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerSingleton("testBeans", tbm);
|
||||
bf.registerSingleton("otherMap", new Properties());
|
||||
|
||||
MapConstructorInjectionBean bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
MapConstructorInjectionBean bean = bf.getBean("annotatedBean", MapConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanMap()).isSameAs(tbm);
|
||||
bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", MapConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanMap()).isSameAs(tbm);
|
||||
}
|
||||
|
||||
@@ -1156,9 +1210,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("myTestBeanMap", tbm);
|
||||
bf.registerSingleton("otherMap", new HashMap<>());
|
||||
|
||||
MapConstructorInjectionBean bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
MapConstructorInjectionBean bean = bf.getBean("annotatedBean", MapConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("myTestBeanMap"));
|
||||
bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", MapConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("myTestBeanMap"));
|
||||
}
|
||||
|
||||
@@ -1173,9 +1227,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerSingleton("testBean1", new TestBean());
|
||||
bf.registerSingleton("testBean2", new TestBean());
|
||||
|
||||
CustomMapConstructorInjectionBean bean = (CustomMapConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
CustomMapConstructorInjectionBean bean = bf.getBean("annotatedBean", CustomMapConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("myTestBeanMap"));
|
||||
bean = (CustomMapConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", CustomMapConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("myTestBeanMap"));
|
||||
}
|
||||
|
||||
@@ -1186,9 +1240,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
bf.registerBeanDefinition("myTestBeanMap", new RootBeanDefinition(HashMap.class));
|
||||
|
||||
QualifiedMapConstructorInjectionBean bean = (QualifiedMapConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
QualifiedMapConstructorInjectionBean bean = bf.getBean("annotatedBean", QualifiedMapConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("myTestBeanMap"));
|
||||
bean = (QualifiedMapConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", QualifiedMapConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanMap()).isSameAs(bf.getBean("myTestBeanMap"));
|
||||
}
|
||||
|
||||
@@ -1203,9 +1257,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerSingleton("testBeans", tbs);
|
||||
bf.registerSingleton("otherSet", new HashSet<>());
|
||||
|
||||
SetConstructorInjectionBean bean = (SetConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
SetConstructorInjectionBean bean = bf.getBean("annotatedBean", SetConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanSet()).isSameAs(tbs);
|
||||
bean = (SetConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", SetConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanSet()).isSameAs(tbs);
|
||||
}
|
||||
|
||||
@@ -1219,9 +1273,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("myTestBeanSet", tbs);
|
||||
bf.registerSingleton("otherSet", new HashSet<>());
|
||||
|
||||
SetConstructorInjectionBean bean = (SetConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
SetConstructorInjectionBean bean = bf.getBean("annotatedBean", SetConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanSet()).isSameAs(bf.getBean("myTestBeanSet"));
|
||||
bean = (SetConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", SetConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanSet()).isSameAs(bf.getBean("myTestBeanSet"));
|
||||
}
|
||||
|
||||
@@ -1234,9 +1288,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
tbs.setUniqueFactoryMethodName("testBeanSet");
|
||||
bf.registerBeanDefinition("myTestBeanSet", tbs);
|
||||
|
||||
CustomSetConstructorInjectionBean bean = (CustomSetConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
CustomSetConstructorInjectionBean bean = bf.getBean("annotatedBean", CustomSetConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanSet()).isSameAs(bf.getBean("myTestBeanSet"));
|
||||
bean = (CustomSetConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
bean = bf.getBean("annotatedBean", CustomSetConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBeanSet()).isSameAs(bf.getBean("myTestBeanSet"));
|
||||
}
|
||||
|
||||
@@ -1244,7 +1298,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
public void testSelfReference() {
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionBean.class));
|
||||
|
||||
SelfInjectionBean bean = (SelfInjectionBean) bf.getBean("annotatedBean");
|
||||
SelfInjectionBean bean = bf.getBean("annotatedBean", SelfInjectionBean.class);
|
||||
assertThat(bean.reference).isSameAs(bean);
|
||||
assertThat(bean.referenceCollection).isNull();
|
||||
}
|
||||
@@ -1254,8 +1308,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionBean.class));
|
||||
bf.registerBeanDefinition("annotatedBean2", new RootBeanDefinition(SelfInjectionBean.class));
|
||||
|
||||
SelfInjectionBean bean = (SelfInjectionBean) bf.getBean("annotatedBean");
|
||||
SelfInjectionBean bean2 = (SelfInjectionBean) bf.getBean("annotatedBean2");
|
||||
SelfInjectionBean bean = bf.getBean("annotatedBean", SelfInjectionBean.class);
|
||||
SelfInjectionBean bean2 = bf.getBean("annotatedBean2", SelfInjectionBean.class);
|
||||
assertThat(bean.reference).isSameAs(bean2);
|
||||
assertThat(bean.referenceCollection.size()).isEqualTo(1);
|
||||
assertThat(bean.referenceCollection.get(0)).isSameAs(bean2);
|
||||
@@ -1265,7 +1319,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
public void testSelfReferenceCollection() {
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionCollectionBean.class));
|
||||
|
||||
SelfInjectionCollectionBean bean = (SelfInjectionCollectionBean) bf.getBean("annotatedBean");
|
||||
SelfInjectionCollectionBean bean = bf.getBean("annotatedBean", SelfInjectionCollectionBean.class);
|
||||
assertThat(bean.reference).isSameAs(bean);
|
||||
assertThat(bean.referenceCollection).isNull();
|
||||
}
|
||||
@@ -1275,8 +1329,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionCollectionBean.class));
|
||||
bf.registerBeanDefinition("annotatedBean2", new RootBeanDefinition(SelfInjectionCollectionBean.class));
|
||||
|
||||
SelfInjectionCollectionBean bean = (SelfInjectionCollectionBean) bf.getBean("annotatedBean");
|
||||
SelfInjectionCollectionBean bean2 = (SelfInjectionCollectionBean) bf.getBean("annotatedBean2");
|
||||
SelfInjectionCollectionBean bean = bf.getBean("annotatedBean", SelfInjectionCollectionBean.class);
|
||||
SelfInjectionCollectionBean bean2 = bf.getBean("annotatedBean2", SelfInjectionCollectionBean.class);
|
||||
assertThat(bean.reference).isSameAs(bean2);
|
||||
assertThat(bean2.referenceCollection.size()).isSameAs(1);
|
||||
assertThat(bean.referenceCollection.get(0)).isSameAs(bean2);
|
||||
@@ -1287,7 +1341,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryFieldInjectionBean.class));
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
ObjectFactoryFieldInjectionBean bean = (ObjectFactoryFieldInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectFactoryFieldInjectionBean bean = bf.getBean("annotatedBean", ObjectFactoryFieldInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
}
|
||||
|
||||
@@ -1296,7 +1350,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryConstructorInjectionBean.class));
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
ObjectFactoryConstructorInjectionBean bean = (ObjectFactoryConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectFactoryConstructorInjectionBean bean = bf.getBean("annotatedBean", ObjectFactoryConstructorInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
}
|
||||
|
||||
@@ -1307,9 +1361,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("annotatedBean", annotatedBeanDefinition);
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
ObjectFactoryFieldInjectionBean bean = (ObjectFactoryFieldInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectFactoryFieldInjectionBean bean = bf.getBean("annotatedBean", ObjectFactoryFieldInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
ObjectFactoryFieldInjectionBean anotherBean = (ObjectFactoryFieldInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectFactoryFieldInjectionBean anotherBean = bf.getBean("annotatedBean", ObjectFactoryFieldInjectionBean.class);
|
||||
assertThat(bean).isNotSameAs(anotherBean);
|
||||
assertThat(anotherBean.getTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
}
|
||||
@@ -1322,7 +1376,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("dependencyBean", bd);
|
||||
bf.registerBeanDefinition("dependencyBean2", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
ObjectFactoryQualifierInjectionBean bean = (ObjectFactoryQualifierInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectFactoryQualifierInjectionBean bean = bf.getBean("annotatedBean", ObjectFactoryQualifierInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("dependencyBean"));
|
||||
}
|
||||
|
||||
@@ -1334,7 +1388,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("dependencyBean", bd);
|
||||
bf.registerBeanDefinition("dependencyBean2", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
ObjectFactoryQualifierInjectionBean bean = (ObjectFactoryQualifierInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectFactoryQualifierInjectionBean bean = bf.getBean("annotatedBean", ObjectFactoryQualifierInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("dependencyBean"));
|
||||
}
|
||||
|
||||
@@ -1344,7 +1398,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
bf.setSerializationId("test");
|
||||
|
||||
ObjectFactoryFieldInjectionBean bean = (ObjectFactoryFieldInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectFactoryFieldInjectionBean bean = bf.getBean("annotatedBean", ObjectFactoryFieldInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
bean = SerializationTestUtils.serializeAndDeserialize(bean);
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
@@ -1357,7 +1411,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
tbd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("testBean", tbd);
|
||||
|
||||
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isEqualTo(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean("myName")).isEqualTo(bf.getBean("testBean", "myName"));
|
||||
assertThat(bean.getOptionalTestBean()).isEqualTo(bf.getBean("testBean"));
|
||||
@@ -1386,7 +1440,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectProviderInjectionBean.class));
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getOptionalTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getOptionalTestBeanWithDefault()).isSameAs(bf.getBean("testBean"));
|
||||
@@ -1413,7 +1467,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
public void testObjectProviderInjectionWithTargetNotAvailable() {
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectProviderInjectionBean.class));
|
||||
|
||||
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class);
|
||||
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(
|
||||
bean::getTestBean);
|
||||
assertThat(bean.getOptionalTestBean()).isNull();
|
||||
@@ -1439,7 +1493,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("testBean1", new RootBeanDefinition(TestBean.class));
|
||||
bf.registerBeanDefinition("testBean2", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class);
|
||||
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(bean::getTestBean);
|
||||
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(bean::getOptionalTestBean);
|
||||
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(bean::consumeOptionalTestBean);
|
||||
@@ -1476,7 +1530,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
tb2.setLazyInit(true);
|
||||
bf.registerBeanDefinition("testBean2", tb2);
|
||||
|
||||
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean1"));
|
||||
assertThat(bean.getOptionalTestBean()).isSameAs(bf.getBean("testBean1"));
|
||||
assertThat(bean.consumeOptionalTestBean()).isSameAs(bf.getBean("testBean1"));
|
||||
@@ -1514,7 +1568,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
tb2.setLazyInit(true);
|
||||
bf.registerBeanDefinition("testBean2", tb2);
|
||||
|
||||
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectProviderInjectionBean bean = bf.getBean("annotatedBean", ObjectProviderInjectionBean.class);
|
||||
List<?> testBeans = bean.sortedTestBeans();
|
||||
assertThat(testBeans.size()).isEqualTo(2);
|
||||
assertThat(testBeans.get(0)).isSameAs(bf.getBean("testBean2"));
|
||||
@@ -1737,7 +1791,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
IntegerRepository ir = new IntegerRepository();
|
||||
bf.registerSingleton("integerRepo", ir);
|
||||
|
||||
RepositoryFieldInjectionBean bean = (RepositoryFieldInjectionBean) bf.getBean("annotatedBean");
|
||||
RepositoryFieldInjectionBean bean = bf.getBean("annotatedBean", RepositoryFieldInjectionBean.class);
|
||||
assertThat(bean.string).isSameAs(sv);
|
||||
assertThat(bean.integer).isSameAs(iv);
|
||||
assertThat(bean.stringArray.length).isSameAs(1);
|
||||
@@ -1782,7 +1836,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
IntegerRepository ir = new IntegerRepository();
|
||||
bf.registerSingleton("integerRepo", ir);
|
||||
|
||||
RepositoryFieldInjectionBeanWithSubstitutedVariables bean = (RepositoryFieldInjectionBeanWithSubstitutedVariables) bf.getBean("annotatedBean");
|
||||
RepositoryFieldInjectionBeanWithSubstitutedVariables bean =
|
||||
bf.getBean("annotatedBean", RepositoryFieldInjectionBeanWithSubstitutedVariables.class);
|
||||
assertThat(bean.string).isSameAs(sv);
|
||||
assertThat(bean.integer).isSameAs(iv);
|
||||
assertThat(bean.stringArray.length).isSameAs(1);
|
||||
@@ -1823,7 +1878,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
IntegerRepository ir = new IntegerRepository();
|
||||
bf.registerSingleton("integerRepo", ir);
|
||||
|
||||
RepositoryFieldInjectionBeanWithQualifiers bean = (RepositoryFieldInjectionBeanWithQualifiers) bf.getBean("annotatedBean");
|
||||
RepositoryFieldInjectionBeanWithQualifiers bean =
|
||||
bf.getBean("annotatedBean", RepositoryFieldInjectionBeanWithQualifiers.class);
|
||||
assertThat(bean.stringRepository).isSameAs(sr);
|
||||
assertThat(bean.integerRepository).isSameAs(ir);
|
||||
assertThat(bean.stringRepositoryArray.length).isSameAs(1);
|
||||
@@ -1860,7 +1916,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
rbd.setQualifiedElement(ReflectionUtils.findField(getClass(), "integerRepositoryQualifierProvider"));
|
||||
bf.registerBeanDefinition("integerRepository", rbd); // Bean name not matching qualifier
|
||||
|
||||
RepositoryFieldInjectionBeanWithQualifiers bean = (RepositoryFieldInjectionBeanWithQualifiers) bf.getBean("annotatedBean");
|
||||
RepositoryFieldInjectionBeanWithQualifiers bean =
|
||||
bf.getBean("annotatedBean", RepositoryFieldInjectionBeanWithQualifiers.class);
|
||||
Repository<?> sr = bf.getBean("stringRepo", Repository.class);
|
||||
Repository<?> ir = bf.getBean("integerRepository", Repository.class);
|
||||
assertThat(bean.stringRepository).isSameAs(sr);
|
||||
@@ -1887,7 +1944,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
bf.registerSingleton("repo", new StringRepository());
|
||||
|
||||
RepositoryFieldInjectionBeanWithSimpleMatch bean = (RepositoryFieldInjectionBeanWithSimpleMatch) bf.getBean("annotatedBean");
|
||||
RepositoryFieldInjectionBeanWithSimpleMatch bean =
|
||||
bf.getBean("annotatedBean", RepositoryFieldInjectionBeanWithSimpleMatch.class);
|
||||
Repository<?> repo = bf.getBean("repo", Repository.class);
|
||||
assertThat(bean.repository).isSameAs(repo);
|
||||
assertThat(bean.stringRepository).isSameAs(repo);
|
||||
@@ -1914,7 +1972,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
bf.registerBeanDefinition("repoFactoryBean", new RootBeanDefinition(RepositoryFactoryBean.class));
|
||||
|
||||
RepositoryFactoryBeanInjectionBean bean = (RepositoryFactoryBeanInjectionBean) bf.getBean("annotatedBean");
|
||||
RepositoryFactoryBeanInjectionBean bean = bf.getBean("annotatedBean", RepositoryFactoryBeanInjectionBean.class);
|
||||
RepositoryFactoryBean<?> repoFactoryBean = bf.getBean("&repoFactoryBean", RepositoryFactoryBean.class);
|
||||
assertThat(bean.repositoryFactoryBean).isSameAs(repoFactoryBean);
|
||||
}
|
||||
@@ -1926,7 +1984,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
bf.registerSingleton("repoFactoryBean", new RepositoryFactoryBean<>());
|
||||
|
||||
RepositoryFactoryBeanInjectionBean bean = (RepositoryFactoryBeanInjectionBean) bf.getBean("annotatedBean");
|
||||
RepositoryFactoryBeanInjectionBean bean = bf.getBean("annotatedBean", RepositoryFactoryBeanInjectionBean.class);
|
||||
RepositoryFactoryBean<?> repoFactoryBean = bf.getBean("&repoFactoryBean", RepositoryFactoryBean.class);
|
||||
assertThat(bean.repositoryFactoryBean).isSameAs(repoFactoryBean);
|
||||
}
|
||||
@@ -1945,7 +2003,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
rbd.getConstructorArgumentValues().addGenericArgumentValue(Repository.class);
|
||||
bf.registerBeanDefinition("repo", rbd);
|
||||
|
||||
RepositoryFieldInjectionBeanWithSimpleMatch bean = (RepositoryFieldInjectionBeanWithSimpleMatch) bf.getBean("annotatedBean");
|
||||
RepositoryFieldInjectionBeanWithSimpleMatch bean = bf.getBean("annotatedBean", RepositoryFieldInjectionBeanWithSimpleMatch.class);
|
||||
Repository<?> repo = bf.getBean("repo", Repository.class);
|
||||
assertThat(bean.repository).isSameAs(repo);
|
||||
assertThat(bean.stringRepository).isSameAs(repo);
|
||||
@@ -1976,7 +2034,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
rbd.getConstructorArgumentValues().addGenericArgumentValue(new TypedStringValue(Repository.class.getName()));
|
||||
bf.registerBeanDefinition("repo", rbd);
|
||||
|
||||
RepositoryFieldInjectionBeanWithSimpleMatch bean = (RepositoryFieldInjectionBeanWithSimpleMatch) bf.getBean("annotatedBean");
|
||||
RepositoryFieldInjectionBeanWithSimpleMatch bean = bf.getBean("annotatedBean", RepositoryFieldInjectionBeanWithSimpleMatch.class);
|
||||
Repository<?> repo = bf.getBean("repo", Repository.class);
|
||||
assertThat(bean.repository).isSameAs(repo);
|
||||
assertThat(bean.stringRepository).isSameAs(repo);
|
||||
@@ -2008,7 +2066,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
IntegerRepository ir = new IntegerRepository();
|
||||
bf.registerSingleton("integerRepo", ir);
|
||||
|
||||
RepositoryMethodInjectionBean bean = (RepositoryMethodInjectionBean) bf.getBean("annotatedBean");
|
||||
RepositoryMethodInjectionBean bean = bf.getBean("annotatedBean", RepositoryMethodInjectionBean.class);
|
||||
assertThat(bean.string).isSameAs(sv);
|
||||
assertThat(bean.integer).isSameAs(iv);
|
||||
assertThat(bean.stringArray.length).isSameAs(1);
|
||||
@@ -2053,7 +2111,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
IntegerRepository ir = new IntegerRepository();
|
||||
bf.registerSingleton("integerRepo", ir);
|
||||
|
||||
RepositoryMethodInjectionBeanWithSubstitutedVariables bean = (RepositoryMethodInjectionBeanWithSubstitutedVariables) bf.getBean("annotatedBean");
|
||||
RepositoryMethodInjectionBeanWithSubstitutedVariables bean =
|
||||
bf.getBean("annotatedBean", RepositoryMethodInjectionBeanWithSubstitutedVariables.class);
|
||||
assertThat(bean.string).isSameAs(sv);
|
||||
assertThat(bean.integer).isSameAs(iv);
|
||||
assertThat(bean.stringArray.length).isSameAs(1);
|
||||
@@ -2094,7 +2153,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
IntegerRepository ir = new IntegerRepository();
|
||||
bf.registerSingleton("integerRepo", ir);
|
||||
|
||||
RepositoryConstructorInjectionBean bean = (RepositoryConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
RepositoryConstructorInjectionBean bean = bf.getBean("annotatedBean", RepositoryConstructorInjectionBean.class);
|
||||
assertThat(bean.stringRepository).isSameAs(sr);
|
||||
assertThat(bean.integerRepository).isSameAs(ir);
|
||||
assertThat(bean.stringRepositoryArray.length).isSameAs(1);
|
||||
@@ -2120,7 +2179,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
GenericRepository gr = new GenericRepository();
|
||||
bf.registerSingleton("genericRepo", gr);
|
||||
|
||||
RepositoryConstructorInjectionBean bean = (RepositoryConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
RepositoryConstructorInjectionBean bean = bf.getBean("annotatedBean", RepositoryConstructorInjectionBean.class);
|
||||
assertThat(bean.stringRepository).isSameAs(gr);
|
||||
assertThat(bean.integerRepository).isSameAs(gr);
|
||||
assertThat(bean.stringRepositoryArray.length).isSameAs(1);
|
||||
@@ -2145,7 +2204,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
SimpleRepository ngr = new SimpleRepository();
|
||||
bf.registerSingleton("simpleRepo", ngr);
|
||||
|
||||
RepositoryConstructorInjectionBean bean = (RepositoryConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
RepositoryConstructorInjectionBean bean = bf.getBean("annotatedBean", RepositoryConstructorInjectionBean.class);
|
||||
assertThat(bean.stringRepository).isSameAs(ngr);
|
||||
assertThat(bean.integerRepository).isSameAs(ngr);
|
||||
assertThat(bean.stringRepositoryArray.length).isSameAs(1);
|
||||
@@ -2173,7 +2232,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
GenericRepository gr = new GenericRepositorySubclass();
|
||||
bf.registerSingleton("genericRepo", gr);
|
||||
|
||||
RepositoryConstructorInjectionBean bean = (RepositoryConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
RepositoryConstructorInjectionBean bean = bf.getBean("annotatedBean", RepositoryConstructorInjectionBean.class);
|
||||
assertThat(bean.stringRepository).isSameAs(sr);
|
||||
assertThat(bean.integerRepository).isSameAs(gr);
|
||||
assertThat(bean.stringRepositoryArray.length).isSameAs(1);
|
||||
@@ -2200,7 +2259,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
SimpleRepository ngr = new SimpleRepositorySubclass();
|
||||
bf.registerSingleton("simpleRepo", ngr);
|
||||
|
||||
RepositoryConstructorInjectionBean bean = (RepositoryConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
RepositoryConstructorInjectionBean bean = bf.getBean("annotatedBean", RepositoryConstructorInjectionBean.class);
|
||||
assertThat(bean.stringRepository).isSameAs(sr);
|
||||
assertThat(bean.integerRepository).isSameAs(ngr);
|
||||
assertThat(bean.stringRepositoryArray.length).isSameAs(1);
|
||||
@@ -3896,6 +3955,20 @@ 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) {
|
||||
|
||||
+15
-24
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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,36 +28,32 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Chris Beams
|
||||
* @since 04.07.2006
|
||||
*/
|
||||
public class DefaultSingletonBeanRegistryTests {
|
||||
class DefaultSingletonBeanRegistryTests {
|
||||
|
||||
private final DefaultSingletonBeanRegistry beanRegistry = new DefaultSingletonBeanRegistry();
|
||||
|
||||
|
||||
@Test
|
||||
public void testSingletons() {
|
||||
DefaultSingletonBeanRegistry beanRegistry = new DefaultSingletonBeanRegistry();
|
||||
|
||||
void singletons() {
|
||||
TestBean tb = new TestBean();
|
||||
beanRegistry.registerSingleton("tb", tb);
|
||||
assertThat(beanRegistry.getSingleton("tb")).isSameAs(tb);
|
||||
|
||||
TestBean tb2 = (TestBean) beanRegistry.getSingleton("tb2", () -> new TestBean());
|
||||
TestBean tb2 = (TestBean) beanRegistry.getSingleton("tb2", TestBean::new);
|
||||
assertThat(beanRegistry.getSingleton("tb2")).isSameAs(tb2);
|
||||
|
||||
assertThat(beanRegistry.getSingleton("tb")).isSameAs(tb);
|
||||
assertThat(beanRegistry.getSingleton("tb2")).isSameAs(tb2);
|
||||
assertThat(beanRegistry.getSingletonCount()).isEqualTo(2);
|
||||
String[] names = beanRegistry.getSingletonNames();
|
||||
assertThat(names.length).isEqualTo(2);
|
||||
assertThat(names[0]).isEqualTo("tb");
|
||||
assertThat(names[1]).isEqualTo("tb2");
|
||||
assertThat(beanRegistry.getSingletonNames()).containsExactly("tb", "tb2");
|
||||
|
||||
beanRegistry.destroySingletons();
|
||||
assertThat(beanRegistry.getSingletonCount()).isEqualTo(0);
|
||||
assertThat(beanRegistry.getSingletonNames().length).isEqualTo(0);
|
||||
assertThat(beanRegistry.getSingletonCount()).isZero();
|
||||
assertThat(beanRegistry.getSingletonNames()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisposableBean() {
|
||||
DefaultSingletonBeanRegistry beanRegistry = new DefaultSingletonBeanRegistry();
|
||||
|
||||
void disposableBean() {
|
||||
DerivedTestBean tb = new DerivedTestBean();
|
||||
beanRegistry.registerSingleton("tb", tb);
|
||||
beanRegistry.registerDisposableBean("tb", tb);
|
||||
@@ -65,21 +61,16 @@ public class DefaultSingletonBeanRegistryTests {
|
||||
|
||||
assertThat(beanRegistry.getSingleton("tb")).isSameAs(tb);
|
||||
assertThat(beanRegistry.getSingletonCount()).isEqualTo(1);
|
||||
String[] names = beanRegistry.getSingletonNames();
|
||||
assertThat(names.length).isEqualTo(1);
|
||||
assertThat(names[0]).isEqualTo("tb");
|
||||
assertThat(beanRegistry.getSingletonNames()).containsExactly("tb");
|
||||
assertThat(tb.wasDestroyed()).isFalse();
|
||||
|
||||
beanRegistry.destroySingletons();
|
||||
assertThat(beanRegistry.getSingletonCount()).isEqualTo(0);
|
||||
assertThat(beanRegistry.getSingletonNames().length).isEqualTo(0);
|
||||
assertThat(tb.wasDestroyed()).isTrue();
|
||||
assertThat(beanRegistry.getSingletonCount()).isZero();
|
||||
assertThat(beanRegistry.getSingletonNames()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDependentRegistration() {
|
||||
DefaultSingletonBeanRegistry beanRegistry = new DefaultSingletonBeanRegistry();
|
||||
|
||||
void dependentRegistration() {
|
||||
beanRegistry.registerDependentBean("a", "b");
|
||||
beanRegistry.registerDependentBean("b", "c");
|
||||
beanRegistry.registerDependentBean("c", "b");
|
||||
|
||||
Vendored
+4
-6
@@ -189,13 +189,11 @@ public class CaffeineCacheManager implements CacheManager {
|
||||
@Override
|
||||
@Nullable
|
||||
public Cache getCache(String name) {
|
||||
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);
|
||||
Cache cache = this.cacheMap.get(name);
|
||||
if (cache == null && this.dynamic) {
|
||||
cache = this.cacheMap.computeIfAbsent(name, this::createCaffeineCache);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vendored
+2
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 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,13 +166,7 @@ public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderA
|
||||
public Cache getCache(String name) {
|
||||
Cache cache = this.cacheMap.get(name);
|
||||
if (cache == null && this.dynamic) {
|
||||
synchronized (this.cacheMap) {
|
||||
cache = this.cacheMap.get(name);
|
||||
if (cache == null) {
|
||||
cache = createConcurrentMapCache(name);
|
||||
this.cacheMap.put(name, cache);
|
||||
}
|
||||
}
|
||||
cache = this.cacheMap.computeIfAbsent(name, this::createConcurrentMapCache);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2023 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();
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 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 no be null");
|
||||
Assert.notNull(this.applicationContext, "ApplicationContext must not be null");
|
||||
return this.applicationContext.getBean(this.beanName);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -749,7 +749,8 @@ 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()));
|
||||
}
|
||||
|
||||
+25
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 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,6 +21,8 @@ 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;
|
||||
@@ -45,15 +47,26 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart
|
||||
}
|
||||
|
||||
|
||||
private static Method findLoadedClassMethod;
|
||||
@Nullable
|
||||
private static final 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 {
|
||||
findLoadedClassMethod = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
|
||||
method = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Invalid [java.lang.ClassLoader] class: no 'findLoadedClass' method defined!");
|
||||
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);
|
||||
}
|
||||
findLoadedClassMethod = method;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,13 +109,14 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart
|
||||
if (isExcluded(className) || ContextTypeMatchClassLoader.this.isExcluded(className)) {
|
||||
return false;
|
||||
}
|
||||
ReflectionUtils.makeAccessible(findLoadedClassMethod);
|
||||
ClassLoader parent = getParent();
|
||||
while (parent != null) {
|
||||
if (ReflectionUtils.invokeMethod(findLoadedClassMethod, parent, className) != null) {
|
||||
return false;
|
||||
if (findLoadedClassMethod != null) {
|
||||
ClassLoader parent = getParent();
|
||||
while (parent != null) {
|
||||
if (ReflectionUtils.invokeMethod(findLoadedClassMethod, parent, className) != null) {
|
||||
return false;
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 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,9 +64,10 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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()
|
||||
*/
|
||||
public void setTimeoutPerShutdownPhase(long timeoutPerShutdownPhase) {
|
||||
this.timeoutPerShutdownPhase = timeoutPerShutdownPhase;
|
||||
|
||||
+2
-2
@@ -206,9 +206,9 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
|
||||
long initialDelay = startTime.getTime() - this.clock.millis();
|
||||
long delay = startTime.getTime() - this.clock.millis();
|
||||
try {
|
||||
return this.scheduledExecutor.schedule(decorateTask(task, false), initialDelay, TimeUnit.MILLISECONDS);
|
||||
return this.scheduledExecutor.schedule(decorateTask(task, false), delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
catch (RejectedExecutionException ex) {
|
||||
throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
|
||||
|
||||
+8
-4
@@ -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 "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>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>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,9 +211,13 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a shutdown on the underlying ExecutorService.
|
||||
* Perform a full shutdown on the underlying ExecutorService,
|
||||
* according to the corresponding configuration settings.
|
||||
* @see #setWaitForTasksToCompleteOnShutdown
|
||||
* @see #setAwaitTerminationMillis
|
||||
* @see java.util.concurrent.ExecutorService#shutdown()
|
||||
* @see java.util.concurrent.ExecutorService#shutdownNow()
|
||||
* @see java.util.concurrent.ExecutorService#awaitTermination
|
||||
*/
|
||||
public void shutdown() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 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 initialDelay = this.scheduledExecutionTime.getTime() - this.triggerContext.getClock().millis();
|
||||
this.currentFuture = this.executor.schedule(this, initialDelay, TimeUnit.MILLISECONDS);
|
||||
long delay = this.scheduledExecutionTime.getTime() - this.triggerContext.getClock().millis();
|
||||
this.currentFuture = this.executor.schedule(this, delay, TimeUnit.MILLISECONDS);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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 initialDelay = startTime.getTime() - this.clock.millis();
|
||||
long delay = startTime.getTime() - this.clock.millis();
|
||||
try {
|
||||
return executor.schedule(errorHandlingTask(task, false), initialDelay, TimeUnit.MILLISECONDS);
|
||||
return executor.schedule(errorHandlingTask(task, false), delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
catch (RejectedExecutionException ex) {
|
||||
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
|
||||
|
||||
@@ -124,8 +124,10 @@ 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.nullSafeConciseToString(this.rejectedValue) + "]; " +
|
||||
"': rejected value [" + ObjectUtils.nullSafeToString(this.rejectedValue) + "]; " +
|
||||
resolvableToString();
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 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 singleton scope
|
||||
* Scope constant for the standard prototype scope
|
||||
* @see org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE
|
||||
*/
|
||||
PROTOTYPE
|
||||
|
||||
+8
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 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,10 +207,9 @@ 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
|
||||
@@ -267,11 +266,10 @@ 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
|
||||
|
||||
+5
-3
@@ -79,7 +79,7 @@ class EnableLoadTimeWeavingTests {
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.DISABLED)
|
||||
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.DISABLED)
|
||||
static class EnableLTWConfig_withAjWeavingDisabled implements LoadTimeWeavingConfigurer {
|
||||
|
||||
@Override
|
||||
@@ -88,8 +88,9 @@ class EnableLoadTimeWeavingTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.AUTODETECT)
|
||||
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.AUTODETECT)
|
||||
static class EnableLTWConfig_withAjWeavingAutodetect implements LoadTimeWeavingConfigurer {
|
||||
|
||||
@Override
|
||||
@@ -98,8 +99,9 @@ class EnableLoadTimeWeavingTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
|
||||
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.ENABLED)
|
||||
static class EnableLTWConfig_withAjWeavingEnabled implements LoadTimeWeavingConfigurer {
|
||||
|
||||
@Override
|
||||
|
||||
+114
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.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;
|
||||
|
||||
@@ -46,6 +47,8 @@ import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* @author Stephane Nicoll
|
||||
* @author Juergen Hoeller
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEventListenerTests {
|
||||
|
||||
@@ -80,16 +83,23 @@ 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, createGenericEventType(String.class));
|
||||
supportsEventType(true, method, createPayloadEventType(String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listenerWithInvalidPayloadAndGenericInformation() {
|
||||
Method method = ReflectionUtils.findMethod(SampleEvents.class, "handleString", String.class);
|
||||
supportsEventType(false, method, createGenericEventType(Integer.class));
|
||||
supportsEventType(false, method, createPayloadEventType(Integer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -113,28 +123,28 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv
|
||||
@Test
|
||||
public void listenerWithAnnotationValue() {
|
||||
Method method = ReflectionUtils.findMethod(SampleEvents.class, "handleStringAnnotationValue");
|
||||
supportsEventType(true, method, createGenericEventType(String.class));
|
||||
supportsEventType(true, method, createPayloadEventType(String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listenerWithAnnotationClasses() {
|
||||
Method method = ReflectionUtils.findMethod(SampleEvents.class, "handleStringAnnotationClasses");
|
||||
supportsEventType(true, method, createGenericEventType(String.class));
|
||||
supportsEventType(true, method, createPayloadEventType(String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listenerWithAnnotationValueAndParameter() {
|
||||
Method method = ReflectionUtils.findMethod(
|
||||
SampleEvents.class, "handleStringAnnotationValueAndParameter", String.class);
|
||||
supportsEventType(true, method, createGenericEventType(String.class));
|
||||
supportsEventType(true, method, createPayloadEventType(String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listenerWithSeveralTypes() {
|
||||
Method method = ReflectionUtils.findMethod(SampleEvents.class, "handleStringOrInteger");
|
||||
supportsEventType(true, method, createGenericEventType(String.class));
|
||||
supportsEventType(true, method, createGenericEventType(Integer.class));
|
||||
supportsEventType(false, method, createGenericEventType(Double.class));
|
||||
supportsEventType(true, method, createPayloadEventType(String.class));
|
||||
supportsEventType(true, method, createPayloadEventType(Integer.class));
|
||||
supportsEventType(false, method, createPayloadEventType(Double.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -325,6 +335,88 @@ 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);
|
||||
@@ -341,7 +433,11 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv
|
||||
return new StaticApplicationListenerMethodAdapter(method, this.sampleEvents);
|
||||
}
|
||||
|
||||
private ResolvableType createGenericEventType(Class<?> payloadType) {
|
||||
private ResolvableType createPayloadEventType(Class<?> payloadType) {
|
||||
return ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, payloadType);
|
||||
}
|
||||
|
||||
private ResolvableType createPayloadEventType(ResolvableType payloadType) {
|
||||
return ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, payloadType);
|
||||
}
|
||||
|
||||
@@ -373,6 +469,14 @@ 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
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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,16 +85,13 @@ public class ReflectiveLoadTimeWeaverTests {
|
||||
|
||||
private int numTimesAddTransformerCalled = 0;
|
||||
|
||||
|
||||
public int getNumTimesGetThrowawayClassLoaderCalled() {
|
||||
return this.numTimesAddTransformerCalled;
|
||||
}
|
||||
|
||||
|
||||
public void addTransformer(ClassFileTransformer transformer) {
|
||||
++this.numTimesAddTransformerCalled;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -102,18 +99,15 @@ public class ReflectiveLoadTimeWeaverTests {
|
||||
|
||||
private int numTimesGetThrowawayClassLoaderCalled = 0;
|
||||
|
||||
|
||||
@Override
|
||||
public int getNumTimesGetThrowawayClassLoaderCalled() {
|
||||
return this.numTimesGetThrowawayClassLoaderCalled;
|
||||
}
|
||||
|
||||
|
||||
public ClassLoader getThrowawayClassLoader() {
|
||||
++this.numTimesGetThrowawayClassLoaderCalled;
|
||||
return getClass().getClassLoader();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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,9 +95,8 @@ 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();
|
||||
}
|
||||
|
||||
@@ -105,9 +104,8 @@ 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();
|
||||
}
|
||||
|
||||
@@ -182,8 +180,7 @@ 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
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 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().size()).isEqualTo(2);
|
||||
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(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().size()).isEqualTo(2);
|
||||
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(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().size()).isEqualTo(1);
|
||||
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(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().size()).isEqualTo(1);
|
||||
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(1);
|
||||
|
||||
Thread.sleep(100);
|
||||
assertThat(ctx.getBean(AtomicInteger.class).get()).isGreaterThanOrEqualTo(10);
|
||||
|
||||
+45
-45
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 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() throws Exception {
|
||||
void submitFailingRunnable() {
|
||||
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() throws Exception {
|
||||
void submitListenableRunnable() {
|
||||
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() throws Exception {
|
||||
void submitFailingListenableRunnable() {
|
||||
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,14 +159,13 @@ 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
|
||||
@@ -178,11 +177,11 @@ abstract class AbstractSchedulingTaskExecutorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void submitFailingCallable() throws Exception {
|
||||
void submitFailingCallable() {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -196,42 +195,41 @@ 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() throws Exception {
|
||||
void submitListenableCallable() {
|
||||
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() throws Exception {
|
||||
void submitFailingListenableCallable() {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -296,8 +294,9 @@ 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;
|
||||
}
|
||||
@@ -329,8 +328,9 @@ 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();
|
||||
|
||||
+5
@@ -89,19 +89,24 @@ 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");
|
||||
|
||||
+11
-11
@@ -41,14 +41,14 @@ import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
|
||||
class ScheduledExecutorFactoryBeanTests {
|
||||
|
||||
@Test
|
||||
void throwsExceptionIfPoolSizeIsLessThanZero() throws Exception {
|
||||
void throwsExceptionIfPoolSizeIsLessThanZero() {
|
||||
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> factory.setPoolSize(-1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("serial")
|
||||
void shutdownNowIsPropagatedToTheExecutorOnDestroy() throws Exception {
|
||||
void shutdownNowIsPropagatedToTheExecutorOnDestroy() {
|
||||
final ScheduledExecutorService executor = mock(ScheduledExecutorService.class);
|
||||
|
||||
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
|
||||
@@ -66,7 +66,7 @@ class ScheduledExecutorFactoryBeanTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("serial")
|
||||
void shutdownIsPropagatedToTheExecutorOnDestroy() throws Exception {
|
||||
void shutdownIsPropagatedToTheExecutorOnDestroy() {
|
||||
final ScheduledExecutorService executor = mock(ScheduledExecutorService.class);
|
||||
|
||||
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
|
||||
@@ -85,7 +85,7 @@ class ScheduledExecutorFactoryBeanTests {
|
||||
|
||||
@Test
|
||||
@EnabledForTestGroups(LONG_RUNNING)
|
||||
void oneTimeExecutionIsSetUpAndFiresCorrectly() throws Exception {
|
||||
void oneTimeExecutionIsSetUpAndFiresCorrectly() {
|
||||
Runnable runnable = mock(Runnable.class);
|
||||
|
||||
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
|
||||
@@ -99,7 +99,7 @@ class ScheduledExecutorFactoryBeanTests {
|
||||
|
||||
@Test
|
||||
@EnabledForTestGroups(LONG_RUNNING)
|
||||
void fixedRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception {
|
||||
void fixedRepeatedExecutionIsSetUpAndFiresCorrectly() {
|
||||
Runnable runnable = mock(Runnable.class);
|
||||
|
||||
ScheduledExecutorTask task = new ScheduledExecutorTask(runnable);
|
||||
@@ -117,7 +117,7 @@ class ScheduledExecutorFactoryBeanTests {
|
||||
|
||||
@Test
|
||||
@EnabledForTestGroups(LONG_RUNNING)
|
||||
void fixedRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception {
|
||||
void fixedRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() {
|
||||
Runnable runnable = mock(Runnable.class);
|
||||
willThrow(new IllegalStateException()).given(runnable).run();
|
||||
|
||||
@@ -137,7 +137,7 @@ class ScheduledExecutorFactoryBeanTests {
|
||||
|
||||
@Test
|
||||
@EnabledForTestGroups(LONG_RUNNING)
|
||||
void withInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception {
|
||||
void withInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectly() {
|
||||
Runnable runnable = mock(Runnable.class);
|
||||
|
||||
ScheduledExecutorTask task = new ScheduledExecutorTask(runnable);
|
||||
@@ -157,7 +157,7 @@ class ScheduledExecutorFactoryBeanTests {
|
||||
|
||||
@Test
|
||||
@EnabledForTestGroups(LONG_RUNNING)
|
||||
void withInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception {
|
||||
void withInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() {
|
||||
Runnable runnable = mock(Runnable.class);
|
||||
willThrow(new IllegalStateException()).given(runnable).run();
|
||||
|
||||
@@ -179,7 +179,7 @@ class ScheduledExecutorFactoryBeanTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("serial")
|
||||
void settingThreadFactoryToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception {
|
||||
void settingThreadFactoryToNullForcesUseOfDefaultButIsOtherwiseCool() {
|
||||
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() throws Exception {
|
||||
void settingRejectedExecutionHandlerToNullForcesUseOfDefaultButIsOtherwiseCool() {
|
||||
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
|
||||
@Override
|
||||
protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
|
||||
@@ -210,7 +210,7 @@ class ScheduledExecutorFactoryBeanTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void objectTypeReportsCorrectType() throws Exception {
|
||||
void objectTypeReportsCorrectType() {
|
||||
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
|
||||
assertThat(factory.getObjectType()).isEqualTo(ScheduledExecutorService.class);
|
||||
}
|
||||
|
||||
+9
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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,8 +67,7 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
|
||||
assertThat(executor.getCorePoolSize()).isEqualTo(1);
|
||||
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isEqualTo(1);
|
||||
|
||||
assertThatThrownBy(() -> executor.setCorePoolSize(-1))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> executor.setCorePoolSize(-1));
|
||||
|
||||
assertThat(executor.getCorePoolSize()).isEqualTo(1);
|
||||
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isEqualTo(1);
|
||||
@@ -90,8 +89,7 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
|
||||
assertThat(executor.getMaxPoolSize()).isEqualTo(1);
|
||||
assertThat(executor.getThreadPoolExecutor().getMaximumPoolSize()).isEqualTo(1);
|
||||
|
||||
assertThatThrownBy(() -> executor.setMaxPoolSize(0))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> executor.setMaxPoolSize(0));
|
||||
|
||||
assertThat(executor.getMaxPoolSize()).isEqualTo(1);
|
||||
assertThat(executor.getThreadPoolExecutor().getMaximumPoolSize()).isEqualTo(1);
|
||||
@@ -113,8 +111,7 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
|
||||
assertThat(executor.getKeepAliveSeconds()).isEqualTo(60);
|
||||
assertThat(executor.getThreadPoolExecutor().getKeepAliveTime(TimeUnit.SECONDS)).isEqualTo(60);
|
||||
|
||||
assertThatThrownBy(() -> executor.setKeepAliveSeconds(-10))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> executor.setKeepAliveSeconds(-10));
|
||||
|
||||
assertThat(executor.getKeepAliveSeconds()).isEqualTo(60);
|
||||
assertThat(executor.getThreadPoolExecutor().getKeepAliveTime(TimeUnit.SECONDS)).isEqualTo(60);
|
||||
@@ -124,8 +121,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
|
||||
@@ -135,8 +132,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,15 +576,17 @@ public class ReflectUtils {
|
||||
c = (Class) lookupDefineClassMethod.invoke(lookup, b);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
throw new CodeGenerationException(ex.getTargetException());
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new CodeGenerationException(ex) {
|
||||
Throwable target = ex.getTargetException();
|
||||
if (target.getClass() != LinkageError.class && target.getClass() != IllegalAccessException.class) {
|
||||
throw new CodeGenerationException(target);
|
||||
}
|
||||
throw new CodeGenerationException(target) {
|
||||
@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();
|
||||
"for ClassLoader.defineClass to be accessible on " + loader.getClass().getName() +
|
||||
"; consider co-locating the affected class in that target ClassLoader instead.";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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,6 +133,9 @@ 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,
|
||||
@@ -545,6 +548,15 @@ 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()) {
|
||||
@@ -556,7 +568,7 @@ public class ResolvableType implements Serializable {
|
||||
try {
|
||||
for (Type genericInterface : resolved.getGenericInterfaces()) {
|
||||
if (genericInterface instanceof Class) {
|
||||
if (forClass((Class<?>) genericInterface).hasGenerics()) {
|
||||
if (((Class<?>) genericInterface).getTypeParameters().length > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -565,7 +577,10 @@ public class ResolvableType implements Serializable {
|
||||
catch (TypeNotPresentException ex) {
|
||||
// Ignore non-present types in generic signature
|
||||
}
|
||||
return getSuperType().hasUnresolvableGenerics();
|
||||
Class<?> superclass = resolved.getSuperclass();
|
||||
if (superclass != null && superclass != Object.class) {
|
||||
return getSuperType().hasUnresolvableGenerics();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ 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;
|
||||
@@ -204,19 +203,18 @@ final class SerializableTypeWrapper {
|
||||
return forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, -1));
|
||||
}
|
||||
else if (Type[].class == method.getReturnType() && ObjectUtils.isEmpty(args)) {
|
||||
Type[] result = new Type[((Type[]) method.invoke(this.provider.getType())).length];
|
||||
Object returnValue = ReflectionUtils.invokeMethod(method, this.provider.getType());
|
||||
if (returnValue == null) {
|
||||
return null;
|
||||
}
|
||||
Type[] result = new Type[((Type[]) returnValue).length];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
return method.invoke(this.provider.getType(), args);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
throw ex.getTargetException();
|
||||
}
|
||||
return ReflectionUtils.invokeMethod(method, this.provider.getType(), args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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, Class<? extends Annotation> annotationType) {
|
||||
return isCandidateClass(clazz, annotationType.getName());
|
||||
public static boolean isCandidateClass(Class<?> clazz, @Nullable Class<? extends Annotation> annotationType) {
|
||||
return (annotationType != null && isCandidateClass(clazz, annotationType.getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2023 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,6 +96,25 @@ public interface Environment extends PropertyResolver {
|
||||
*/
|
||||
String[] getDefaultProfiles();
|
||||
|
||||
/**
|
||||
* Determine whether one of the given profile expressions matches the
|
||||
* {@linkplain #getActiveProfiles() active profiles} — 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 — 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 — or
|
||||
* in the case of no explicit {@linkplain #getActiveProfiles() active profiles},
|
||||
@@ -118,25 +137,6 @@ public interface Environment extends PropertyResolver {
|
||||
@Deprecated
|
||||
boolean acceptsProfiles(String... profiles);
|
||||
|
||||
/**
|
||||
* Determine whether one of the given profile expressions matches the
|
||||
* {@linkplain #getActiveProfiles() active profiles} — 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 — 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} — or in the case
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 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,13 +33,15 @@ 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 URL.
|
||||
* Always supports resolution as {@code java.net.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 {
|
||||
|
||||
@@ -124,7 +126,7 @@ public class ClassPathResource extends AbstractFileResolvingResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ClassLoader that this resource will be obtained from.
|
||||
* Return the {@link ClassLoader} that this resource will be obtained from.
|
||||
*/
|
||||
@Nullable
|
||||
public final ClassLoader getClassLoader() {
|
||||
@@ -134,8 +136,8 @@ public class ClassPathResource extends AbstractFileResolvingResource {
|
||||
|
||||
/**
|
||||
* This implementation checks for the resolution of a resource URL.
|
||||
* @see java.lang.ClassLoader#getResource(String)
|
||||
* @see java.lang.Class#getResource(String)
|
||||
* @see ClassLoader#getResource(String)
|
||||
* @see Class#getResource(String)
|
||||
*/
|
||||
@Override
|
||||
public boolean exists() {
|
||||
@@ -145,8 +147,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 java.lang.ClassLoader#getResource(String)
|
||||
* @see java.lang.Class#getResource(String)
|
||||
* @see ClassLoader#getResource(String)
|
||||
* @see Class#getResource(String)
|
||||
*/
|
||||
@Override
|
||||
public boolean isReadable() {
|
||||
@@ -179,9 +181,11 @@ public class ClassPathResource extends AbstractFileResolvingResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation opens an InputStream for the given class path resource.
|
||||
* @see java.lang.ClassLoader#getResourceAsStream(String)
|
||||
* @see java.lang.Class#getResourceAsStream(String)
|
||||
* 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)
|
||||
*/
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
@@ -204,8 +208,8 @@ public class ClassPathResource extends AbstractFileResolvingResource {
|
||||
/**
|
||||
* This implementation returns a URL for the underlying class path resource,
|
||||
* if available.
|
||||
* @see java.lang.ClassLoader#getResource(String)
|
||||
* @see java.lang.Class#getResource(String)
|
||||
* @see ClassLoader#getResource(String)
|
||||
* @see Class#getResource(String)
|
||||
*/
|
||||
@Override
|
||||
public URL getURL() throws IOException {
|
||||
@@ -217,9 +221,9 @@ public class ClassPathResource extends AbstractFileResolvingResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* This implementation creates a {@code ClassPathResource}, applying the given
|
||||
* path relative to the path used to create this descriptor.
|
||||
* @see StringUtils#applyRelativePath(String, String)
|
||||
*/
|
||||
@Override
|
||||
public Resource createRelative(String relativePath) {
|
||||
@@ -231,7 +235,7 @@ public class ClassPathResource extends AbstractFileResolvingResource {
|
||||
/**
|
||||
* This implementation returns the name of the file that this class path
|
||||
* resource refers to.
|
||||
* @see org.springframework.util.StringUtils#getFilename(String)
|
||||
* @see StringUtils#getFilename(String)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
@@ -277,8 +281,7 @@ 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-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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,6 +158,7 @@ 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() {
|
||||
@@ -169,6 +170,8 @@ 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() {
|
||||
@@ -177,8 +180,8 @@ public class FileSystemResource extends AbstractResource implements WritableReso
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation opens a NIO file stream for the underlying file.
|
||||
* @see java.io.FileInputStream
|
||||
* This implementation opens an NIO file stream for the underlying file.
|
||||
* @see java.nio.file.Files#newInputStream(Path, java.nio.file.OpenOption...)
|
||||
*/
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
@@ -195,6 +198,8 @@ 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() {
|
||||
@@ -204,7 +209,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
|
||||
|
||||
/**
|
||||
* This implementation opens a FileOutputStream for the underlying file.
|
||||
* @see java.io.FileOutputStream
|
||||
* @see java.nio.file.Files#newOutputStream(Path, java.nio.file.OpenOption...)
|
||||
*/
|
||||
@Override
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
@@ -214,6 +219,7 @@ 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 {
|
||||
@@ -223,6 +229,7 @@ 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 {
|
||||
@@ -324,6 +331,7 @@ 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() {
|
||||
@@ -334,6 +342,7 @@ 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() {
|
||||
@@ -342,7 +351,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
|
||||
|
||||
|
||||
/**
|
||||
* This implementation compares the underlying File references.
|
||||
* This implementation compares the underlying file paths.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(@Nullable Object other) {
|
||||
@@ -351,7 +360,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the hash code of the underlying File reference.
|
||||
* This implementation returns the hash code of the underlying file path.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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 PathResource from a Path handle.
|
||||
* Create a new {@code PathResource} from a {@link 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" → "C:/dir1/dir2"!
|
||||
@@ -73,7 +73,7 @@ public class PathResource extends AbstractResource implements WritableResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new PathResource from a Path handle.
|
||||
* Create a new {@code PathResource} from a path string.
|
||||
* <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" → "C:/dir1/dir2"!
|
||||
@@ -86,7 +86,7 @@ public class PathResource extends AbstractResource implements WritableResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new PathResource from a Path handle.
|
||||
* Create a new {@code PathResource} from a {@link URI}.
|
||||
* <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" → "C:/dir1/dir2"!
|
||||
@@ -127,7 +127,7 @@ public class PathResource extends AbstractResource implements WritableResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation opens a InputStream for the underlying file.
|
||||
* This implementation opens an {@link 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 a OutputStream for the underlying file.
|
||||
* This implementation opens an {@link 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 URL for the underlying file.
|
||||
* This implementation returns a {@link 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 URI for the underlying file.
|
||||
* This implementation returns a {@link 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 File reference.
|
||||
* This implementation returns the underlying {@link File} reference.
|
||||
*/
|
||||
@Override
|
||||
public File getFile() throws IOException {
|
||||
@@ -207,7 +207,7 @@ public class PathResource extends AbstractResource implements WritableResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation opens a Channel for the underlying file.
|
||||
* This implementation opens a {@link ReadableByteChannel} 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 Channel for the underlying file.
|
||||
* This implementation opens a {@link WritableByteChannel} 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 PathResource, applying the given path
|
||||
* This implementation creates a {@link 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 Path references.
|
||||
* This implementation compares the underlying {@link 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 Path reference.
|
||||
* This implementation returns the hash code of the underlying {@link Path} reference.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
@@ -16,18 +16,26 @@
|
||||
|
||||
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;
|
||||
|
||||
@@ -61,6 +69,9 @@ 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 = "[...]";
|
||||
|
||||
|
||||
/**
|
||||
@@ -923,19 +934,31 @@ 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:
|
||||
* 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}.
|
||||
* 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}.
|
||||
* @param obj the object to build a string representation for
|
||||
* @return a concise string representation of the supplied object
|
||||
* @since 5.3.27
|
||||
@@ -946,9 +969,33 @@ 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);
|
||||
}
|
||||
@@ -964,7 +1011,10 @@ public abstract class ObjectUtils {
|
||||
|
||||
/**
|
||||
* Derived from {@link org.springframework.beans.BeanUtils#isSimpleValueType}.
|
||||
* As of 5.3.28, considering {@code UUID} in addition to the bean-level check.
|
||||
* <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}.
|
||||
*/
|
||||
private static boolean isSimpleValueType(Class<?> type) {
|
||||
return (Void.class != type && void.class != type &&
|
||||
@@ -974,10 +1024,18 @@ public abstract class ObjectUtils {
|
||||
Number.class.isAssignableFrom(type) ||
|
||||
Date.class.isAssignableFrom(type) ||
|
||||
Temporal.class.isAssignableFrom(type) ||
|
||||
UUID.class == 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) ||
|
||||
URI.class == type ||
|
||||
URL.class == type ||
|
||||
UUID.class == type ||
|
||||
Locale.class == type ||
|
||||
Pattern.class == type ||
|
||||
Class.class == type));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 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,16 +509,8 @@ public abstract class ReflectionUtils {
|
||||
* @see java.lang.Object#equals(Object)
|
||||
*/
|
||||
public static boolean isEqualsMethod(@Nullable Method method) {
|
||||
if (method == null) {
|
||||
return false;
|
||||
}
|
||||
if (method.getParameterCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (!method.getName().equals("equals")) {
|
||||
return false;
|
||||
}
|
||||
return method.getParameterTypes()[0] == Object.class;
|
||||
return (method != null && method.getParameterCount() == 1 && method.getName().equals("equals") &&
|
||||
method.getParameterTypes()[0] == Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -526,7 +518,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"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+43
-58
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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,20 +342,31 @@ class DefaultConversionServiceTests {
|
||||
|
||||
@Test
|
||||
void convertArrayToCollectionInterface() {
|
||||
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");
|
||||
@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");
|
||||
}
|
||||
|
||||
@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((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));
|
||||
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);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -383,10 +394,9 @@ class DefaultConversionServiceTests {
|
||||
|
||||
@Test
|
||||
void convertArrayToCollectionImpl() {
|
||||
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");
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<String> result = conversionService.convert(new String[] {"1", "2", "3"}, ArrayList.class);
|
||||
assertThat(result).isExactlyInstanceOf(ArrayList.class).containsExactly("1", "2", "3");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -416,34 +426,25 @@ class DefaultConversionServiceTests {
|
||||
@Test
|
||||
void convertStringToArray() {
|
||||
String[] result = conversionService.convert("1,2,3", String[].class);
|
||||
assertThat(result.length).isEqualTo(3);
|
||||
assertThat(result[0]).isEqualTo("1");
|
||||
assertThat(result[1]).isEqualTo("2");
|
||||
assertThat(result[2]).isEqualTo("3");
|
||||
assertThat(result).containsExactly("1", "2", "3");
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertStringToArrayWithElementConversion() {
|
||||
Integer[] result = conversionService.convert("1,2,3", Integer[].class);
|
||||
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));
|
||||
assertThat(result).containsExactly(1, 2, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertStringToPrimitiveArrayWithElementConversion() {
|
||||
int[] result = conversionService.convert("1,2,3", int[].class);
|
||||
assertThat(result.length).isEqualTo(3);
|
||||
assertThat(result[0]).isEqualTo(1);
|
||||
assertThat(result[1]).isEqualTo(2);
|
||||
assertThat(result[2]).isEqualTo(3);
|
||||
assertThat(result).containsExactly(1, 2, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertEmptyStringToArray() {
|
||||
String[] result = conversionService.convert("", String[].class);
|
||||
assertThat(result.length).isEqualTo(0);
|
||||
assertThat(result).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -457,7 +458,7 @@ class DefaultConversionServiceTests {
|
||||
void convertArrayToObjectWithElementConversion() {
|
||||
String[] array = new String[] {"3"};
|
||||
Integer result = conversionService.convert(array, Integer.class);
|
||||
assertThat((int) result).isEqualTo((int) Integer.valueOf(3));
|
||||
assertThat(result).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -470,39 +471,27 @@ class DefaultConversionServiceTests {
|
||||
@Test
|
||||
void convertObjectToArray() {
|
||||
Object[] result = conversionService.convert(3L, Object[].class);
|
||||
assertThat(result.length).isEqualTo(1);
|
||||
assertThat(result[0]).isEqualTo(3L);
|
||||
assertThat(result).containsExactly(3L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertObjectToArrayWithElementConversion() {
|
||||
Integer[] result = conversionService.convert(3L, Integer[].class);
|
||||
assertThat(result.length).isEqualTo(1);
|
||||
assertThat((int) result[0]).isEqualTo((int) Integer.valueOf(3));
|
||||
assertThat(result).containsExactly(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertCollectionToArray() {
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add("1");
|
||||
list.add("2");
|
||||
list.add("3");
|
||||
List<String> list = Arrays.asList("1", "2", "3");
|
||||
String[] result = conversionService.convert(list, String[].class);
|
||||
assertThat(result[0]).isEqualTo("1");
|
||||
assertThat(result[1]).isEqualTo("2");
|
||||
assertThat(result[2]).isEqualTo("3");
|
||||
assertThat(result).containsExactly("1", "2", "3");
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertCollectionToArrayWithElementConversion() {
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add("1");
|
||||
list.add("2");
|
||||
list.add("3");
|
||||
List<String> list = Arrays.asList("1", "2", "3");
|
||||
Integer[] result = conversionService.convert(list, Integer[].class);
|
||||
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));
|
||||
assertThat(result).containsExactly(1, 2, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -522,34 +511,30 @@ class DefaultConversionServiceTests {
|
||||
|
||||
@Test
|
||||
void convertStringToCollection() {
|
||||
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");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> result = conversionService.convert("1,2,3", List.class);
|
||||
assertThat(result).containsExactly("1", "2", "3");
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertStringToCollectionWithElementConversion() throws Exception {
|
||||
List<?> result = (List<?>) conversionService.convert("1,2,3", TypeDescriptor.valueOf(String.class),
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Integer> result = (List<Integer>) conversionService.convert("1,2,3", TypeDescriptor.valueOf(String.class),
|
||||
new TypeDescriptor(getClass().getField("genericList")));
|
||||
assertThat(result.size()).isEqualTo(3);
|
||||
assertThat(result.get(0)).isEqualTo(1);
|
||||
assertThat(result.get(1)).isEqualTo(2);
|
||||
assertThat(result.get(2)).isEqualTo(3);
|
||||
assertThat(result).containsExactly(1, 2, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertEmptyStringToCollection() {
|
||||
Collection<?> result = conversionService.convert("", Collection.class);
|
||||
assertThat(result.size()).isEqualTo(0);
|
||||
assertThat(result).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertCollectionToObject() {
|
||||
List<Long> list = Collections.singletonList(3L);
|
||||
Long result = conversionService.convert(list, Long.class);
|
||||
assertThat(result).isEqualTo(Long.valueOf(3));
|
||||
assertThat(result).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -16,21 +16,34 @@
|
||||
|
||||
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.util.ArrayList;
|
||||
import java.time.ZoneId;
|
||||
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;
|
||||
@@ -224,7 +237,7 @@ class ObjectUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void addObjectToNullArray() throws Exception {
|
||||
void addObjectToNullArray() {
|
||||
String newElement = "foo";
|
||||
String[] newArray = ObjectUtils.addObjectToArray(null, newElement);
|
||||
assertThat(newArray).hasSize(1);
|
||||
@@ -232,14 +245,14 @@ class ObjectUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void addNullObjectToNullArray() throws Exception {
|
||||
void addNullObjectToNullArray() {
|
||||
Object[] newArray = ObjectUtils.addObjectToArray(null, null);
|
||||
assertThat(newArray).hasSize(1);
|
||||
assertThat(newArray[0]).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullSafeEqualsWithArrays() throws Exception {
|
||||
void nullSafeEqualsWithArrays() {
|
||||
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();
|
||||
}
|
||||
@@ -849,6 +862,41 @@ 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");
|
||||
@@ -881,11 +929,19 @@ class ObjectUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullSafeConciseToStringForNumber() {
|
||||
void nullSafeConciseToStringForPrimitivesAndWrappers() {
|
||||
assertThat(ObjectUtils.nullSafeConciseToString(true)).isEqualTo("true");
|
||||
assertThat(ObjectUtils.nullSafeConciseToString('X')).isEqualTo("X");
|
||||
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();
|
||||
@@ -904,6 +960,30 @@ 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";
|
||||
@@ -928,19 +1008,100 @@ 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 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));
|
||||
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("{...}");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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,4 +102,47 @@ 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-2018 the original author or authors.
|
||||
* Copyright 2002-2023 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,8 +47,9 @@ public class LogFactoryService extends LogFactory {
|
||||
}
|
||||
|
||||
|
||||
// Just in case some code happens to call uncommon Commons Logging methods...
|
||||
// Just in case some code happens to rely on Commons Logging attributes...
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, Object value) {
|
||||
if (value != null) {
|
||||
this.attributes.put(name, value);
|
||||
@@ -58,19 +59,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-2012 the original author or authors.
|
||||
* Copyright 2002-2023 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,11 +44,22 @@ public class SQLWarningException extends UncategorizedDataAccessException {
|
||||
super(msg, ex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the underlying SQLWarning.
|
||||
* Return the underlying {@link SQLWarning}.
|
||||
* @since 5.3.29
|
||||
*/
|
||||
public SQLWarning SQLWarning() {
|
||||
public SQLWarning getSQLWarning() {
|
||||
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-2020 the original author or authors.
|
||||
* Copyright 2002-2023 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,12 +187,14 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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()
|
||||
* @see java.sql.SQLWarning
|
||||
* @see org.springframework.jdbc.SQLWarningException
|
||||
* @see #handleWarnings
|
||||
* @see #handleWarnings(Statement)
|
||||
*/
|
||||
public void setIgnoreWarnings(boolean ignoreWarnings) {
|
||||
this.ignoreWarnings = ignoreWarnings;
|
||||
@@ -385,6 +387,9 @@ 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;
|
||||
@@ -658,6 +663,9 @@ 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);
|
||||
@@ -1197,6 +1205,9 @@ 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);
|
||||
@@ -1494,13 +1505,44 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an SQLWarningException if we're not ignoring warnings,
|
||||
* otherwise log the warnings at debug level.
|
||||
* 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.
|
||||
* @param stmt the current JDBC statement
|
||||
* @throws SQLWarningException if not ignoring warnings
|
||||
* @see org.springframework.jdbc.SQLWarningException
|
||||
* @param ex the primary exception after failed statement execution
|
||||
* @since 5.3.29
|
||||
* @see #handleWarnings(Statement)
|
||||
* @see SQLException#setNextException
|
||||
*/
|
||||
protected void handleWarnings(Statement stmt) throws SQLException {
|
||||
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 {
|
||||
if (isIgnoreWarnings()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
SQLWarning warningToLog = stmt.getWarnings();
|
||||
@@ -1517,7 +1559,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an SQLWarningException if encountering an actual warning.
|
||||
* Throw a {@link 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-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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,8114,8115</value>
|
||||
<value>544,2628,8114,8115</value>
|
||||
</property>
|
||||
<property name="dataAccessResourceFailureCodes">
|
||||
<value>4060</value>
|
||||
|
||||
+7
-6
@@ -125,18 +125,19 @@ public abstract class AbstractJmsListeningContainer extends JmsDestinationAccess
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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()
|
||||
*/
|
||||
public void setPhase(int phase) {
|
||||
this.phase = phase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the phase in which this container will be started and stopped.
|
||||
* Return the lifecycle phase in which this container will be started and stopped.
|
||||
* @see #setPhase
|
||||
*/
|
||||
@Override
|
||||
public int getPhase() {
|
||||
|
||||
+4
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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() {
|
||||
int args = this.method.getParameterCount();
|
||||
return getBeanType().getSimpleName() + "#" + this.method.getName() + "[" + args + " args]";
|
||||
return getBeanType().getSimpleName() + "#" + this.method.getName() +
|
||||
"[" + this.method.getParameterCount() + " args]";
|
||||
}
|
||||
|
||||
|
||||
@@ -365,13 +365,11 @@ 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() + "] " +
|
||||
|
||||
+4
-2
@@ -613,11 +613,12 @@ public class ResolvableMethod {
|
||||
|
||||
private static class MethodInvocationInterceptor implements MethodInterceptor, InvocationHandler {
|
||||
|
||||
@Nullable
|
||||
private Method invokedMethod;
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) {
|
||||
public Object intercept(Object object, Method method, @Nullable Object[] args, @Nullable MethodProxy proxy) {
|
||||
if (ReflectionUtils.isObjectMethod(method)) {
|
||||
return ReflectionUtils.invokeMethod(method, object, args);
|
||||
}
|
||||
@@ -629,10 +630,11 @@ public class ResolvableMethod {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
public Object invoke(Object proxy, Method method, @Nullable Object[] args) {
|
||||
return intercept(proxy, method, args, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Method getInvokedMethod() {
|
||||
return this.invokedMethod;
|
||||
}
|
||||
|
||||
+6
-4
@@ -100,13 +100,11 @@ 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.transaction.jta.JtaTransactionManager
|
||||
* @see org.springframework.orm.jpa.JpaTransactionManager
|
||||
* @see org.springframework.orm.jpa.vendor.HibernateJpaDialect
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class HibernateTransactionManager extends AbstractPlatformTransactionManager
|
||||
@@ -271,7 +269,11 @@ 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;
|
||||
}
|
||||
|
||||
+16
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 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,14 +180,23 @@ public final class SpringBeanContainer implements BeanContainer {
|
||||
|
||||
try {
|
||||
if (lifecycleOptions.useJpaCompliantCreation()) {
|
||||
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));
|
||||
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);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return new SpringContainedBean<>(this.beanFactory.getBean(name, beanType));
|
||||
return (this.beanFactory.containsBean(name) ?
|
||||
new SpringContainedBean<>(this.beanFactory.getBean(name, beanType)) :
|
||||
new SpringContainedBean<>(this.beanFactory.getBean(beanType)));
|
||||
}
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
|
||||
+7
-10
@@ -29,7 +29,6 @@ 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;
|
||||
@@ -162,7 +161,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doGetTransaction(TransactionSynchronizationManager synchronizationManager) throws TransactionException {
|
||||
protected Object doGetTransaction(TransactionSynchronizationManager synchronizationManager) {
|
||||
ConnectionFactoryTransactionObject txObject = new ConnectionFactoryTransactionObject();
|
||||
ConnectionHolder conHolder = (ConnectionHolder) synchronizationManager.getResource(obtainConnectionFactory());
|
||||
txObject.setConnectionHolder(conHolder, false);
|
||||
@@ -178,7 +177,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
protected Mono<Void> doBegin(TransactionSynchronizationManager synchronizationManager, Object transaction,
|
||||
TransactionDefinition definition) throws TransactionException {
|
||||
TransactionDefinition definition) {
|
||||
|
||||
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) transaction;
|
||||
|
||||
@@ -243,9 +242,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Mono<Object> doSuspend(TransactionSynchronizationManager synchronizationManager, Object transaction)
|
||||
throws TransactionException {
|
||||
|
||||
protected Mono<Object> doSuspend(TransactionSynchronizationManager synchronizationManager, Object transaction) {
|
||||
return Mono.defer(() -> {
|
||||
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) transaction;
|
||||
txObject.setConnectionHolder(null);
|
||||
@@ -255,7 +252,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
|
||||
|
||||
@Override
|
||||
protected Mono<Void> doResume(TransactionSynchronizationManager synchronizationManager,
|
||||
@Nullable Object transaction, Object suspendedResources) throws TransactionException {
|
||||
@Nullable Object transaction, Object suspendedResources) {
|
||||
|
||||
return Mono.defer(() -> {
|
||||
synchronizationManager.bindResource(obtainConnectionFactory(), suspendedResources);
|
||||
@@ -265,7 +262,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
|
||||
|
||||
@Override
|
||||
protected Mono<Void> doCommit(TransactionSynchronizationManager TransactionSynchronizationManager,
|
||||
GenericReactiveTransaction status) throws TransactionException {
|
||||
GenericReactiveTransaction status) {
|
||||
|
||||
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) status.getTransaction();
|
||||
Connection connection = txObject.getConnectionHolder().getConnection();
|
||||
@@ -278,7 +275,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
|
||||
|
||||
@Override
|
||||
protected Mono<Void> doRollback(TransactionSynchronizationManager TransactionSynchronizationManager,
|
||||
GenericReactiveTransaction status) throws TransactionException {
|
||||
GenericReactiveTransaction status) {
|
||||
|
||||
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) status.getTransaction();
|
||||
Connection connection = txObject.getConnectionHolder().getConnection();
|
||||
@@ -291,7 +288,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
|
||||
|
||||
@Override
|
||||
protected Mono<Void> doSetRollbackOnly(TransactionSynchronizationManager synchronizationManager,
|
||||
GenericReactiveTransaction status) throws TransactionException {
|
||||
GenericReactiveTransaction status) {
|
||||
|
||||
return Mono.fromRunnable(() -> {
|
||||
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) status.getTransaction();
|
||||
|
||||
+10
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 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>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.
|
||||
* <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.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
@@ -81,12 +81,9 @@ 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>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.
|
||||
* <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.
|
||||
* @param status object returned by the {@code getTransaction} method
|
||||
* @throws UnexpectedRollbackException in case of an unexpected rollback
|
||||
* that the transaction coordinator initiated
|
||||
@@ -110,6 +107,8 @@ 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)
|
||||
|
||||
+16
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 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,6 +46,8 @@ 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
|
||||
@@ -58,8 +60,7 @@ public interface ReactiveTransactionManager extends TransactionManager {
|
||||
* @see TransactionDefinition#getTimeout
|
||||
* @see TransactionDefinition#isReadOnly
|
||||
*/
|
||||
Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition definition)
|
||||
throws TransactionException;
|
||||
Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition definition);
|
||||
|
||||
/**
|
||||
* Commit the given transaction, with regard to its status. If the transaction
|
||||
@@ -69,14 +70,12 @@ 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
|
||||
* throwing an exception, the transaction must be fully completed and
|
||||
* propagating an exception, the transaction must be fully completed and
|
||||
* cleaned up. No rollback call should be expected in such a case.
|
||||
* <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.
|
||||
* <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.
|
||||
* @param transaction object returned by the {@code getTransaction} method
|
||||
* @throws UnexpectedRollbackException in case of an unexpected rollback
|
||||
* that the transaction coordinator initiated
|
||||
@@ -88,7 +87,7 @@ public interface ReactiveTransactionManager extends TransactionManager {
|
||||
* is already completed (that is, committed or rolled back)
|
||||
* @see ReactiveTransaction#setRollbackOnly
|
||||
*/
|
||||
Mono<Void> commit(ReactiveTransaction transaction) throws TransactionException;
|
||||
Mono<Void> commit(ReactiveTransaction transaction);
|
||||
|
||||
/**
|
||||
* Perform a rollback of the given transaction.
|
||||
@@ -96,16 +95,20 @@ 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 threw an exception.</b>
|
||||
* <p><b>Do not call rollback on a transaction if commit failed.</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) throws TransactionException;
|
||||
Mono<Void> rollback(ReactiveTransaction transaction);
|
||||
|
||||
}
|
||||
|
||||
+18
-34
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 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,9 +95,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
|
||||
* @see #doBegin
|
||||
*/
|
||||
@Override
|
||||
public final Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition definition)
|
||||
throws TransactionException {
|
||||
|
||||
public final Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition definition) {
|
||||
// Use defaults if no transaction definition given.
|
||||
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
|
||||
|
||||
@@ -165,7 +163,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) throws TransactionException {
|
||||
TransactionDefinition definition, Object transaction, boolean debugEnabled) {
|
||||
|
||||
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
|
||||
return Mono.error(new IllegalTransactionStateException(
|
||||
@@ -277,7 +275,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
|
||||
* @see #resume
|
||||
*/
|
||||
private Mono<SuspendedResourcesHolder> suspend(TransactionSynchronizationManager synchronizationManager,
|
||||
@Nullable Object transaction) throws TransactionException {
|
||||
@Nullable Object transaction) {
|
||||
|
||||
if (synchronizationManager.isSynchronizationActive()) {
|
||||
Mono<List<TransactionSynchronization>> suspendedSynchronizations = doSuspendSynchronization(synchronizationManager);
|
||||
@@ -325,8 +323,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
|
||||
* @see #suspend
|
||||
*/
|
||||
private Mono<Void> resume(TransactionSynchronizationManager synchronizationManager,
|
||||
@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)
|
||||
throws TransactionException {
|
||||
@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder) {
|
||||
|
||||
Mono<Void> resume = Mono.empty();
|
||||
|
||||
@@ -403,7 +400,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
|
||||
* @see #rollback
|
||||
*/
|
||||
@Override
|
||||
public final Mono<Void> commit(ReactiveTransaction transaction) throws TransactionException {
|
||||
public final Mono<Void> commit(ReactiveTransaction transaction) {
|
||||
if (transaction.isCompleted()) {
|
||||
return Mono.error(new IllegalTransactionStateException(
|
||||
"Transaction is already completed - do not call commit or rollback more than once per transaction"));
|
||||
@@ -426,10 +423,9 @@ 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) throws TransactionException {
|
||||
GenericReactiveTransaction status) {
|
||||
|
||||
AtomicBoolean beforeCompletionInvoked = new AtomicBoolean();
|
||||
|
||||
@@ -487,7 +483,7 @@ public abstract class AbstractReactiveTransactionManager implements ReactiveTran
|
||||
* @see #doSetRollbackOnly
|
||||
*/
|
||||
@Override
|
||||
public final Mono<Void> rollback(ReactiveTransaction transaction) throws TransactionException {
|
||||
public final Mono<Void> rollback(ReactiveTransaction transaction) {
|
||||
if (transaction.isCompleted()) {
|
||||
return Mono.error(new IllegalTransactionStateException(
|
||||
"Transaction is already completed - do not call commit or rollback more than once per transaction"));
|
||||
@@ -503,7 +499,6 @@ 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) {
|
||||
@@ -542,11 +537,10 @@ 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) throws TransactionException {
|
||||
GenericReactiveTransaction status, Throwable ex) {
|
||||
|
||||
return Mono.defer(() -> {
|
||||
if (status.isNewTransaction()) {
|
||||
@@ -714,14 +708,12 @@ 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)
|
||||
throws TransactionException;
|
||||
protected abstract Object doGetTransaction(TransactionSynchronizationManager synchronizationManager);
|
||||
|
||||
/**
|
||||
* Check if the given transaction object indicates an existing transaction
|
||||
@@ -735,10 +727,9 @@ 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) throws TransactionException {
|
||||
protected boolean isExistingTransaction(Object transaction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -757,12 +748,11 @@ 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) throws TransactionException;
|
||||
Object transaction, TransactionDefinition definition);
|
||||
|
||||
/**
|
||||
* Suspend the resources of the current transaction.
|
||||
@@ -775,11 +765,10 @@ 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) throws TransactionException {
|
||||
Object transaction) {
|
||||
|
||||
throw new TransactionSuspensionNotSupportedException(
|
||||
"Transaction manager [" + getClass().getName() + "] does not support transaction suspension");
|
||||
@@ -796,11 +785,10 @@ 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) throws TransactionException {
|
||||
@Nullable Object transaction, Object suspendedResources) {
|
||||
|
||||
throw new TransactionSuspensionNotSupportedException(
|
||||
"Transaction manager [" + getClass().getName() + "] does not support transaction suspension");
|
||||
@@ -830,11 +818,10 @@ 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) throws TransactionException;
|
||||
GenericReactiveTransaction status);
|
||||
|
||||
/**
|
||||
* Perform an actual rollback of the given transaction.
|
||||
@@ -843,11 +830,10 @@ 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) throws TransactionException;
|
||||
GenericReactiveTransaction status);
|
||||
|
||||
/**
|
||||
* Set the given transaction rollback-only. Only called on rollback
|
||||
@@ -857,10 +843,9 @@ 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) throws TransactionException {
|
||||
GenericReactiveTransaction status) {
|
||||
|
||||
throw new IllegalTransactionStateException(
|
||||
"Participating in existing transactions is not supported - when 'isExistingTransaction' " +
|
||||
@@ -878,13 +863,12 @@ 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) throws TransactionException {
|
||||
Object transaction, List<TransactionSynchronization> synchronizations) {
|
||||
|
||||
logger.debug("Cannot register Spring after-completion synchronization with existing transaction - " +
|
||||
"processing Spring after-completion callbacks immediately, with outcome status 'unknown'");
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 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.debug("TransactionSynchronization.beforeCompletion threw exception", t)).then();
|
||||
logger.error("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.debug("TransactionSynchronization.afterCompletion threw exception", t)).then();
|
||||
.onErrorContinue((t, o) -> logger.error("TransactionSynchronization.afterCompletion threw exception", t)).then();
|
||||
}
|
||||
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 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.debug("TransactionSynchronization.beforeCompletion threw exception", ex);
|
||||
logger.error("TransactionSynchronization.beforeCompletion threw exception", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,7 +172,7 @@ public abstract class TransactionSynchronizationUtils {
|
||||
synchronization.afterCompletion(completionStatus);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("TransactionSynchronization.afterCompletion threw exception", ex);
|
||||
logger.error("TransactionSynchronization.afterCompletion threw exception", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -580,7 +580,7 @@ public class Jackson2ObjectMapperBuilder {
|
||||
* @see com.fasterxml.jackson.databind.Module
|
||||
*/
|
||||
public Jackson2ObjectMapperBuilder modulesToInstall(Module... modules) {
|
||||
this.modules = Arrays.asList(modules);
|
||||
this.modules = new ArrayList<>(Arrays.asList(modules));
|
||||
this.findWellKnownModules = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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 ServletContextResource.
|
||||
* Create a new {@code ServletContextResource} for the given path.
|
||||
* <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,6 +94,7 @@ 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-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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,6 +218,7 @@ public class HandlerMethod {
|
||||
this.description = handlerMethod.description;
|
||||
}
|
||||
|
||||
|
||||
private MethodParameter[] initMethodParameters() {
|
||||
int count = this.bridgedMethod.getParameterCount();
|
||||
MethodParameter[] result = new MethodParameter[count];
|
||||
@@ -248,7 +249,7 @@ public class HandlerMethod {
|
||||
for (Class<?> paramType : method.getParameterTypes()) {
|
||||
joiner.add(paramType.getSimpleName());
|
||||
}
|
||||
return beanType.getName() + "#" + method.getName() + joiner.toString();
|
||||
return beanType.getName() + "#" + method.getName() + joiner;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+13
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.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
|
||||
@@ -96,6 +97,17 @@ 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
|
||||
|
||||
+42
-29
@@ -229,26 +229,6 @@ 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()
|
||||
@@ -351,14 +331,15 @@ 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) {
|
||||
@@ -369,6 +350,38 @@ 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();
|
||||
@@ -381,7 +394,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();
|
||||
@@ -393,7 +406,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();
|
||||
@@ -472,7 +485,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)
|
||||
|
||||
+4
-2
@@ -617,11 +617,12 @@ public class ResolvableMethod {
|
||||
|
||||
private static class MethodInvocationInterceptor implements MethodInterceptor, InvocationHandler {
|
||||
|
||||
@Nullable
|
||||
private Method invokedMethod;
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) {
|
||||
public Object intercept(Object object, Method method, @Nullable Object[] args, @Nullable MethodProxy proxy) {
|
||||
if (ReflectionUtils.isObjectMethod(method)) {
|
||||
return ReflectionUtils.invokeMethod(method, object, args);
|
||||
}
|
||||
@@ -633,10 +634,11 @@ public class ResolvableMethod {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
public Object invoke(Object proxy, Method method, @Nullable Object[] args) {
|
||||
return intercept(proxy, method, args, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Method getInvokedMethod() {
|
||||
return this.invokedMethod;
|
||||
}
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 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,12 +43,11 @@ 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
|
||||
|
||||
+4
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 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,10 +109,9 @@ public abstract class RequestPredicates {
|
||||
*/
|
||||
public static RequestPredicate path(String pattern) {
|
||||
Assert.notNull(pattern, "'pattern' must not be null");
|
||||
if (!pattern.isEmpty() && !pattern.startsWith("/")) {
|
||||
pattern = "/" + pattern;
|
||||
}
|
||||
return pathPredicates(PathPatternParser.defaultInstance).apply(pattern);
|
||||
PathPatternParser parser = PathPatternParser.defaultInstance;
|
||||
pattern = parser.initFullPathPattern(pattern);
|
||||
return pathPredicates(parser).apply(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
-13
@@ -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,8 +211,9 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
|
||||
Object resolvedHandler = handler;
|
||||
|
||||
// Parse path pattern
|
||||
urlPath = prependLeadingSlash(urlPath);
|
||||
PathPattern pattern = getPathPatternParser().parse(urlPath);
|
||||
PathPatternParser parser = getPathPatternParser();
|
||||
urlPath = parser.initFullPathPattern(urlPath);
|
||||
PathPattern pattern = parser.parse(urlPath);
|
||||
if (this.handlerMap.containsKey(pattern)) {
|
||||
Object existingHandler = this.handlerMap.get(pattern);
|
||||
if (existingHandler != null && existingHandler != resolvedHandler) {
|
||||
@@ -241,14 +242,4 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 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,7 +35,6 @@ 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;
|
||||
@@ -86,8 +85,9 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
|
||||
public void registerHandlers(Map<String, ResourceWebHandler> handlerMap) {
|
||||
this.handlerMap.clear();
|
||||
handlerMap.forEach((rawPattern, resourceWebHandler) -> {
|
||||
rawPattern = prependLeadingSlash(rawPattern);
|
||||
PathPattern pattern = PathPatternParser.defaultInstance.parse(rawPattern);
|
||||
PathPatternParser parser = PathPatternParser.defaultInstance;
|
||||
rawPattern = parser.initFullPathPattern(rawPattern);
|
||||
PathPattern pattern = parser.parse(rawPattern);
|
||||
this.handlerMap.put(pattern, resourceWebHandler);
|
||||
});
|
||||
}
|
||||
@@ -173,14 +173,4 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private static String prependLeadingSlash(String pattern) {
|
||||
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
|
||||
return "/" + pattern;
|
||||
}
|
||||
else {
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 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,11 +602,9 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<PathPattern> result = new ArrayList<>(patterns.length);
|
||||
for (String path : patterns) {
|
||||
if (StringUtils.hasText(path) && !path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
result.add(parser.parse(path));
|
||||
for (String pattern : patterns) {
|
||||
pattern = parser.initFullPathPattern(pattern);
|
||||
result.add(parser.parse(pattern));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 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
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 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
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
||||
+4
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 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,10 +108,9 @@ public abstract class RequestPredicates {
|
||||
*/
|
||||
public static RequestPredicate path(String pattern) {
|
||||
Assert.notNull(pattern, "'pattern' must not be null");
|
||||
if (!pattern.isEmpty() && !pattern.startsWith("/")) {
|
||||
pattern = "/" + pattern;
|
||||
}
|
||||
return pathPredicates(PathPatternParser.defaultInstance).apply(pattern);
|
||||
PathPatternParser parser = PathPatternParser.defaultInstance;
|
||||
pattern = parser.initFullPathPattern(pattern);
|
||||
return pathPredicates(parser).apply(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
||||
+12
-1
@@ -51,6 +51,7 @@ 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
|
||||
@@ -327,10 +328,15 @@ 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 = (StringUtils.hasLength(pattern) && !pattern.startsWith("/") ? "/" + pattern : pattern);
|
||||
pattern = initFullPathPattern(pattern);
|
||||
Object previousPath = request.getAttribute(this.pathAttributeName);
|
||||
request.setAttribute(this.pathAttributeName, this.lookupPath);
|
||||
try {
|
||||
@@ -341,6 +347,11 @@ 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 {
|
||||
|
||||
+3
-5
@@ -75,11 +75,9 @@ public final class PathPatternsRequestCondition extends AbstractRequestCondition
|
||||
return EMPTY_PATH_PATTERN;
|
||||
}
|
||||
SortedSet<PathPattern> result = new TreeSet<>();
|
||||
for (String path : patterns) {
|
||||
if (StringUtils.hasText(path) && !path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
result.add(parser.parse(path));
|
||||
for (String pattern : patterns) {
|
||||
pattern = parser.initFullPathPattern(pattern);
|
||||
result.add(parser.parse(pattern));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+2
-3
@@ -35,6 +35,7 @@ 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
|
||||
@@ -156,9 +157,7 @@ public class PatternsRequestCondition extends AbstractRequestCondition<PatternsR
|
||||
}
|
||||
Set<String> result = new LinkedHashSet<>(patterns.length);
|
||||
for (String pattern : patterns) {
|
||||
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
|
||||
pattern = "/" + pattern;
|
||||
}
|
||||
pattern = PathPatternParser.defaultInstance.initFullPathPattern(pattern);
|
||||
result.add(pattern);
|
||||
}
|
||||
return result;
|
||||
|
||||
+4
-5
@@ -65,6 +65,7 @@ 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}
|
||||
@@ -544,9 +545,7 @@ public class MvcUriComponentsBuilder {
|
||||
String typePath = getClassMapping(controllerType);
|
||||
String methodPath = getMethodMapping(method);
|
||||
String path = pathMatcher.combine(typePath, methodPath);
|
||||
if (StringUtils.hasLength(path) && !path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
path = PathPatternParser.defaultInstance.initFullPathPattern(path);
|
||||
builder.path(path);
|
||||
|
||||
return applyContributors(builder, method, args);
|
||||
@@ -742,8 +741,8 @@ public class MvcUriComponentsBuilder {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
return intercept(proxy, method, args, null);
|
||||
public Object invoke(Object proxy, Method method, @Nullable Object[] args) {
|
||||
return intercept(proxy, method, (args != null ? args : new Object[0]), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 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
-3
@@ -287,6 +287,14 @@ 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();
|
||||
@@ -296,11 +304,27 @@ public class MvcUriComponentsBuilderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromMethodCallOnSubclass() {
|
||||
UriComponents uriComponents = fromMethodCall(on(ExtendedController.class).myMethod(null)).build();
|
||||
public void fromMethodCallPlainWithNoArguments() {
|
||||
UriComponents uriComponents = fromMethodCall(on(ControllerWithMethods.class).myMethod()).build();
|
||||
|
||||
assertThat(uriComponents.toUriString()).startsWith("http://localhost");
|
||||
assertThat(uriComponents.toUriString()).endsWith("/extended/else");
|
||||
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");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -553,6 +577,11 @@ public class MvcUriComponentsBuilderTests {
|
||||
return null;
|
||||
}
|
||||
|
||||
@RequestMapping("/noarg")
|
||||
HttpEntity<Void> myMethod() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@RequestMapping("/{id}/foo")
|
||||
HttpEntity<Void> methodWithPathVariable(@PathVariable String id) {
|
||||
return null;
|
||||
@@ -594,6 +623,17 @@ 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 {
|
||||
|
||||
|
||||
@@ -1455,7 +1455,6 @@ 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
|
||||
@@ -1835,17 +1834,17 @@ The following listing shows the bean declarations:
|
||||
----
|
||||
<tx:annotation-driven/>
|
||||
|
||||
<bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
|
||||
<bean id="transactionManager1" class="org.springframework.jdbc.support.JdbcTransactionManager">
|
||||
...
|
||||
<qualifier value="order"/>
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
|
||||
<bean id="transactionManager2" class="org.springframework.jdbc.support.JdbcTransactionManager">
|
||||
...
|
||||
<qualifier value="account"/>
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager3" class="org.springframework.data.r2dbc.connectionfactory.R2dbcTransactionManager">
|
||||
<bean id="transactionManager3" class="org.springframework.data.r2dbc.connection.R2dbcTransactionManager">
|
||||
...
|
||||
<qualifier value="reactive-account"/>
|
||||
</bean>
|
||||
@@ -3024,10 +3023,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
|
||||
@@ -3157,30 +3156,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.springfamework.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.springframework.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
|
||||
@@ -3804,7 +3803,9 @@ 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.
|
||||
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`.
|
||||
|
||||
`SQLErrorCodeSQLExceptionTranslator` is the implementation of `SQLExceptionTranslator`
|
||||
that is used by default. This implementation uses specific vendor codes. It is more
|
||||
@@ -3830,8 +3831,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.
|
||||
|
||||
@@ -3864,12 +3865,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
|
||||
@@ -3877,7 +3878,6 @@ 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,7 +3886,6 @@ translator:
|
||||
CustomSQLErrorCodesTranslator tr = new CustomSQLErrorCodesTranslator();
|
||||
tr.setDataSource(dataSource);
|
||||
this.jdbcTemplate.setExceptionTranslator(tr);
|
||||
|
||||
}
|
||||
|
||||
public void updateShippingCharge(long orderId, long pct) {
|
||||
@@ -4260,8 +4259,12 @@ 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 thread-bound connections with, for example, `DataSourceTransactionManager`.
|
||||
`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.
|
||||
|
||||
|
||||
[[jdbc-SmartDataSource]]
|
||||
@@ -4300,7 +4303,6 @@ In contrast to `DriverManagerDataSource`, it reuses the same connection all the
|
||||
avoiding excessive creation of physical connections.
|
||||
|
||||
|
||||
|
||||
[[jdbc-DriverManagerDataSource]]
|
||||
==== Using `DriverManagerDataSource`
|
||||
|
||||
@@ -4336,29 +4338,47 @@ javadoc for more details.
|
||||
|
||||
|
||||
[[jdbc-DataSourceTransactionManager]]
|
||||
==== Using `DataSourceTransactionManager`
|
||||
==== Using `DataSourceTransactionManager` / `JdbcTransactionManager`
|
||||
|
||||
The `DataSourceTransactionManager` class is a `PlatformTransactionManager`
|
||||
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.
|
||||
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`.
|
||||
|
||||
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 this transaction manager, the lookup strategy
|
||||
behaves exactly like the common one. Thus, it can be used in any case.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
====
|
||||
|
||||
|
||||
|
||||
@@ -4373,13 +4393,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
|
||||
@@ -7276,19 +7296,16 @@ javadoc for more details.
|
||||
==== Using `R2dbcTransactionManager`
|
||||
|
||||
The `R2dbcTransactionManager` class is a `ReactiveTransactionManager` implementation for
|
||||
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.
|
||||
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`.
|
||||
|
||||
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()`.
|
||||
`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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
@@ -8457,7 +8474,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 `PersistenceExceptions` to Spring `DataAccessExceptions`
|
||||
* Advanced translation of `PersistenceException` to Spring's `DataAccessException`
|
||||
|
||||
This is particularly valuable for special transaction semantics and for advanced
|
||||
translation of exception. The default implementation (`DefaultJpaDialect`) does
|
||||
|
||||
Reference in New Issue
Block a user