diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreator.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreator.java
index 8ab713d01e2..a9a3f88a919 100644
--- a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreator.java
+++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/BeanNameAutoProxyCreator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2020 the original author or authors.
+ * Copyright 2002-2025 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.
@@ -112,10 +112,10 @@ public class BeanNameAutoProxyCreator extends AbstractAutoProxyCreator {
boolean isFactoryBean = FactoryBean.class.isAssignableFrom(beanClass);
for (String mappedName : this.beanNames) {
if (isFactoryBean) {
- if (!mappedName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
+ if (mappedName.isEmpty() || mappedName.charAt(0) != BeanFactory.FACTORY_BEAN_PREFIX_CHAR) {
continue;
}
- mappedName = mappedName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
+ mappedName = mappedName.substring(1); // length of '&'
}
if (isMatch(beanName, mappedName)) {
return true;
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
index 8e113a729f7..27f79597627 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2023 the original author or authors.
+ * Copyright 2002-2025 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.
@@ -125,9 +125,16 @@ public interface BeanFactory {
* beans created by the FactoryBean. For example, if the bean named
* {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
* will return the factory, not the instance returned by the factory.
+ * @see #FACTORY_BEAN_PREFIX_CHAR
*/
String FACTORY_BEAN_PREFIX = "&";
+ /**
+ * Character variant of {@link #FACTORY_BEAN_PREFIX}.
+ * @since 6.2.6
+ */
+ char FACTORY_BEAN_PREFIX_CHAR = '&';
+
/**
* Return an instance, which may be shared or independent, of the specified bean.
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactoryUtils.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactoryUtils.java
index 2e9580b6c6f..3f6921f22ee 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactoryUtils.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactoryUtils.java
@@ -73,7 +73,7 @@ public abstract class BeanFactoryUtils {
* @see BeanFactory#FACTORY_BEAN_PREFIX
*/
public static boolean isFactoryDereference(@Nullable String name) {
- return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
+ return (name != null && !name.isEmpty() && name.charAt(0) == BeanFactory.FACTORY_BEAN_PREFIX_CHAR);
}
/**
@@ -85,14 +85,14 @@ public abstract class BeanFactoryUtils {
*/
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
- if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
+ if (name.isEmpty() || name.charAt(0) != BeanFactory.FACTORY_BEAN_PREFIX_CHAR) {
return name;
}
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
- beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
+ beanName = beanName.substring(1); // length of '&'
}
- while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
+ while (beanName.charAt(0) == BeanFactory.FACTORY_BEAN_PREFIX_CHAR);
return beanName;
});
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java
index dee9a440a0b..181705b16a5 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java
@@ -762,16 +762,16 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
public String[] getAliases(String name) {
String beanName = transformedBeanName(name);
List aliases = new ArrayList<>();
- boolean factoryPrefix = name.startsWith(FACTORY_BEAN_PREFIX);
+ boolean hasFactoryPrefix = (!name.isEmpty() && name.charAt(0) == BeanFactory.FACTORY_BEAN_PREFIX_CHAR);
String fullBeanName = beanName;
- if (factoryPrefix) {
+ if (hasFactoryPrefix) {
fullBeanName = FACTORY_BEAN_PREFIX + beanName;
}
if (!fullBeanName.equals(name)) {
aliases.add(fullBeanName);
}
String[] retrievedAliases = super.getAliases(beanName);
- String prefix = (factoryPrefix ? FACTORY_BEAN_PREFIX : "");
+ String prefix = (hasFactoryPrefix ? FACTORY_BEAN_PREFIX : "");
for (String retrievedAlias : retrievedAliases) {
String alias = prefix + retrievedAlias;
if (!alias.equals(name)) {
@@ -1137,7 +1137,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {
String beanName = transformedBeanName(name);
// Efficiently check whether bean definition exists in this factory.
- if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory parent) {
+ if (getParentBeanFactory() instanceof ConfigurableBeanFactory parent && !containsBeanDefinition(beanName)) {
return parent.getMergedBeanDefinition(beanName);
}
// Resolve merged bean definition locally.
@@ -1276,7 +1276,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
*/
protected String originalBeanName(String name) {
String beanName = transformedBeanName(name);
- if (name.startsWith(FACTORY_BEAN_PREFIX)) {
+ if (!name.isEmpty() && name.charAt(0) == BeanFactory.FACTORY_BEAN_PREFIX_CHAR) {
beanName = FACTORY_BEAN_PREFIX + beanName;
}
return beanName;
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java
index 087fae9432e..05b303e455e 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java
@@ -362,9 +362,9 @@ class ConfigurationClassEnhancer {
// proxy that intercepts calls to getObject() and returns any cached bean instance.
// This ensures that the semantics of calling a FactoryBean from within @Bean methods
// is the same as that of referring to a FactoryBean within XML. See SPR-6602.
- if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
- factoryContainsBean(beanFactory, beanName)) {
- Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
+ String factoryBeanName = BeanFactory.FACTORY_BEAN_PREFIX + beanName;
+ if (factoryContainsBean(beanFactory, factoryBeanName) && factoryContainsBean(beanFactory, beanName)) {
+ Object factoryBean = beanFactory.getBean(factoryBeanName);
if (factoryBean instanceof ScopedProxyFactoryBean) {
// Scoped proxy factory beans are a special case and should not be further proxied
}
diff --git a/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java b/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java
index 97d48897ac7..af524d54d61 100644
--- a/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java
+++ b/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2025 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.
@@ -926,8 +926,8 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
*/
private boolean isExcluded(String beanName) {
return (this.excludedBeans.contains(beanName) ||
- (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX) &&
- this.excludedBeans.contains(beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()))));
+ (!beanName.isEmpty() && (beanName.charAt(0) == BeanFactory.FACTORY_BEAN_PREFIX_CHAR) &&
+ this.excludedBeans.contains(beanName.substring(1)))); // length of '&'
}
/**
diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java
index 5274214e5bf..96d61a5986a 100644
--- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java
+++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java
@@ -350,6 +350,7 @@ abstract class AnnotationsScanner {
private static boolean isOverride(Method rootMethod, Method candidateMethod) {
return (!Modifier.isPrivate(candidateMethod.getModifiers()) &&
+ candidateMethod.getParameterCount() == rootMethod.getParameterCount() &&
candidateMethod.getName().equals(rootMethod.getName()) &&
hasSameParameterTypes(rootMethod, candidateMethod));
}
diff --git a/spring-core/src/main/java/org/springframework/util/ClassUtils.java b/spring-core/src/main/java/org/springframework/util/ClassUtils.java
index 1e15e291c89..34623b1fbea 100644
--- a/spring-core/src/main/java/org/springframework/util/ClassUtils.java
+++ b/spring-core/src/main/java/org/springframework/util/ClassUtils.java
@@ -614,10 +614,11 @@ public abstract class ClassUtils {
Class> resolvedPrimitive = primitiveWrapperTypeMap.get(rhsType);
return (lhsType == resolvedPrimitive);
}
- else {
+ else if (rhsType.isPrimitive()) {
Class> resolvedWrapper = primitiveTypeToWrapperMap.get(rhsType);
return (resolvedWrapper != null && lhsType.isAssignableFrom(resolvedWrapper));
}
+ return false;
}
/**