Consistent processing of overridden bean methods

Closes gh-28286
This commit is contained in:
Juergen Hoeller
2024-02-21 18:36:03 +01:00
parent 2a1b30dbed
commit f5397d6426
5 changed files with 103 additions and 19 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@@ -16,6 +16,8 @@
package org.springframework.context.annotation;
import java.util.Map;
import org.springframework.beans.factory.parsing.Problem;
import org.springframework.beans.factory.parsing.ProblemReporter;
import org.springframework.core.type.MethodMetadata;
@@ -52,22 +54,24 @@ final class BeanMethod extends ConfigurationMethod {
return;
}
if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName())) {
if (!getMetadata().isOverridable()) {
// instance @Bean methods within @Configuration classes must be overridable to accommodate CGLIB
problemReporter.error(new NonOverridableMethodError());
}
Map<String, Object> attributes =
getConfigurationClass().getMetadata().getAnnotationAttributes(Configuration.class.getName());
if (attributes != null && (Boolean) attributes.get("proxyBeanMethods") && !getMetadata().isOverridable()) {
// instance @Bean methods within @Configuration classes must be overridable to accommodate CGLIB
problemReporter.error(new NonOverridableMethodError());
}
}
@Override
public boolean equals(@Nullable Object other) {
return (this == other || (other instanceof BeanMethod that && this.metadata.equals(that.metadata)));
return (this == other || (other instanceof BeanMethod that &&
this.configurationClass.equals(that.configurationClass) &&
getLocalMethodIdentifier(this.metadata).equals(getLocalMethodIdentifier(that.metadata))));
}
@Override
public int hashCode() {
return this.metadata.hashCode();
return this.configurationClass.hashCode() * 31 + getLocalMethodIdentifier(this.metadata).hashCode();
}
@Override
@@ -76,6 +80,14 @@ final class BeanMethod extends ConfigurationMethod {
}
private static String getLocalMethodIdentifier(MethodMetadata metadata) {
String metadataString = metadata.toString();
int index = metadataString.indexOf(metadata.getDeclaringClassName());
return (index >= 0 ? metadataString.substring(index + metadata.getDeclaringClassName().length()) :
metadataString);
}
private class VoidDeclaredMethodError extends Problem {
VoidDeclaredMethodError() {

View File

@@ -223,13 +223,12 @@ final class ConfigurationClass {
Map<String, Object> attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName());
// A configuration class may not be final (CGLIB limitation) unless it declares proxyBeanMethods=false
if (attributes != null && (Boolean) attributes.get("proxyBeanMethods")) {
if (this.metadata.isFinal()) {
problemReporter.error(new FinalConfigurationProblem());
}
for (BeanMethod beanMethod : this.beanMethods) {
beanMethod.validate(problemReporter);
}
if (attributes != null && (Boolean) attributes.get("proxyBeanMethods") && this.metadata.isFinal()) {
problemReporter.error(new FinalConfigurationProblem());
}
for (BeanMethod beanMethod : this.beanMethods) {
beanMethod.validate(problemReporter);
}
// A configuration class may not contain overloaded bean methods unless it declares enforceUniqueMethods=false

View File

@@ -53,6 +53,7 @@ import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.core.type.StandardMethodMetadata;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
@@ -229,8 +230,12 @@ class ConfigurationClassBeanDefinitionReader {
beanDef.setUniqueFactoryMethodName(methodName);
}
if (metadata instanceof StandardMethodMetadata sam) {
beanDef.setResolvedFactoryMethod(sam.getIntrospectedMethod());
if (metadata instanceof StandardMethodMetadata smm &&
configClass.getMetadata() instanceof StandardAnnotationMetadata sam) {
Method method = ClassUtils.getMostSpecificMethod(smm.getIntrospectedMethod(), sam.getIntrospectedClass());
if (method == smm.getIntrospectedMethod()) {
beanDef.setResolvedFactoryMethod(method);
}
}
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);