Merge branch '6.0.x'
This commit is contained in:
commit
2a77665be7
|
|
@ -638,7 +638,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||||
* Resolve the specified cached method argument or field value.
|
* Resolve the specified cached method argument or field value.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private Object resolvedCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) {
|
private Object resolveCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) {
|
||||||
if (cachedArgument instanceof DependencyDescriptor descriptor) {
|
if (cachedArgument instanceof DependencyDescriptor descriptor) {
|
||||||
Assert.state(this.beanFactory != null, "No BeanFactory available");
|
Assert.state(this.beanFactory != null, "No BeanFactory available");
|
||||||
return this.beanFactory.resolveDependency(descriptor, beanName, null, null);
|
return this.beanFactory.resolveDependency(descriptor, beanName, null, null);
|
||||||
|
|
@ -683,10 +683,12 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||||
Object value;
|
Object value;
|
||||||
if (this.cached) {
|
if (this.cached) {
|
||||||
try {
|
try {
|
||||||
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
|
value = resolveCachedArgument(beanName, this.cachedFieldValue);
|
||||||
}
|
}
|
||||||
catch (NoSuchBeanDefinitionException ex) {
|
catch (BeansException ex) {
|
||||||
// Unexpected removal of target bean for cached argument -> re-resolve
|
// 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);
|
value = resolveFieldValue(field, bean, beanName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -715,9 +717,8 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||||
}
|
}
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (!this.cached) {
|
if (!this.cached) {
|
||||||
Object cachedFieldValue = null;
|
|
||||||
if (value != null || this.required) {
|
if (value != null || this.required) {
|
||||||
cachedFieldValue = desc;
|
Object cachedFieldValue = desc;
|
||||||
registerDependentBeans(beanName, autowiredBeanNames);
|
registerDependentBeans(beanName, autowiredBeanNames);
|
||||||
if (value != null && autowiredBeanNames.size() == 1) {
|
if (value != null && autowiredBeanNames.size() == 1) {
|
||||||
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
||||||
|
|
@ -727,9 +728,13 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||||
desc, autowiredBeanName, field.getType());
|
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;
|
return value;
|
||||||
|
|
@ -760,10 +765,12 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||||
Object[] arguments;
|
Object[] arguments;
|
||||||
if (this.cached) {
|
if (this.cached) {
|
||||||
try {
|
try {
|
||||||
arguments = resolveCachedArguments(beanName);
|
arguments = resolveCachedArguments(beanName, this.cachedMethodArguments);
|
||||||
}
|
}
|
||||||
catch (NoSuchBeanDefinitionException ex) {
|
catch (BeansException ex) {
|
||||||
// Unexpected removal of target bean for cached argument -> re-resolve
|
// 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);
|
arguments = resolveMethodArguments(method, bean, beanName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -782,14 +789,13 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Object[] resolveCachedArguments(@Nullable String beanName) {
|
private Object[] resolveCachedArguments(@Nullable String beanName, @Nullable Object[] cachedMethodArguments) {
|
||||||
Object[] cachedMethodArguments = this.cachedMethodArguments;
|
|
||||||
if (cachedMethodArguments == null) {
|
if (cachedMethodArguments == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Object[] arguments = new Object[cachedMethodArguments.length];
|
Object[] arguments = new Object[cachedMethodArguments.length];
|
||||||
for (int i = 0; i < arguments.length; i++) {
|
for (int i = 0; i < arguments.length; i++) {
|
||||||
arguments[i] = resolvedCachedArgument(beanName, cachedMethodArguments[i]);
|
arguments[i] = resolveCachedArgument(beanName, cachedMethodArguments[i]);
|
||||||
}
|
}
|
||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
|
|
@ -822,7 +828,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (!this.cached) {
|
if (!this.cached) {
|
||||||
if (arguments != null) {
|
if (arguments != null) {
|
||||||
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
|
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, argumentCount);
|
||||||
registerDependentBeans(beanName, autowiredBeans);
|
registerDependentBeans(beanName, autowiredBeans);
|
||||||
if (autowiredBeans.size() == argumentCount) {
|
if (autowiredBeans.size() == argumentCount) {
|
||||||
Iterator<String> it = autowiredBeans.iterator();
|
Iterator<String> it = autowiredBeans.iterator();
|
||||||
|
|
@ -837,11 +843,12 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.cachedMethodArguments = cachedMethodArguments;
|
this.cachedMethodArguments = cachedMethodArguments;
|
||||||
|
this.cached = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.cachedMethodArguments = null;
|
this.cachedMethodArguments = null;
|
||||||
|
// cached flag remains false
|
||||||
}
|
}
|
||||||
this.cached = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return arguments;
|
return arguments;
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,59 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
assertThat(bean.getTestBean3()).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();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void extendedResourceInjection() {
|
void extendedResourceInjection() {
|
||||||
RootBeanDefinition bd = new RootBeanDefinition(TypedExtendedResourceInjectionBean.class);
|
RootBeanDefinition bd = new RootBeanDefinition(TypedExtendedResourceInjectionBean.class);
|
||||||
|
|
@ -3881,6 +3934,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 static class ProvidedArgumentBean {
|
||||||
|
|
||||||
public ProvidedArgumentBean(String[] args) {
|
public ProvidedArgumentBean(String[] args) {
|
||||||
|
|
|
||||||
|
|
@ -124,8 +124,10 @@ public class FieldError extends ObjectError {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
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 +
|
return "Field error in object '" + getObjectName() + "' on field '" + this.field +
|
||||||
"': rejected value [" + ObjectUtils.nullSafeConciseToString(this.rejectedValue) + "]; " +
|
"': rejected value [" + ObjectUtils.nullSafeToString(this.rejectedValue) + "]; " +
|
||||||
resolvableToString();
|
resolvableToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue