Affects: Spring Framework 7.0.8 (regression since 6.0)
Summary
AbstractNestablePropertyAccessor / BeanWrapperImpl discovers public static getter methods as JavaBean properties. A @ConfigurationProperties class with public static Xxx getInstance() gets a read-only property named instance that returns the singleton object. This is a regression from Spring
Framework 5.x where CachedIntrospectionResults explicitly filtered static methods via Modifier.isStatic().
Root Cause
Spring Framework 6.0 replaced java.beans.Introspector-based property discovery with a custom "efficient method reflection pass." This reflection pass no longer checks Modifier.isStatic() on discovered getter methods, so public static getters like getInstance(), getBean() are registered as bean
properties alongside actual instance properties.
Reproduction
@ConfigurationProperties("app")
public class AppSettings {
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
// Static getter — NOT a bean property, but BeanWrapperImpl treats it as one
public static AppSettings getBean() {
return SpringUtils.tryGetBean(AppSettings.class).orElseGet(AppSettings::new);
}
}
BeanWrapperImpl wrapper = new BeanWrapperImpl(new AppSettings());
for (PropertyDescriptor pd : wrapper.getPropertyDescriptors()) {
System.out.println(pd.getName()); // prints: "bean", "class", "name"
}
// Expected: only "name" and "class"
// Actual: "bean" also appears — static method incorrectly treated as instance property
Impact
This causes downstream failures. Most critically, spring-cloud-context 5.0.2's ConfigurationPropertiesRebinder.resetProperties() recurses into read-only non-simple properties. When the static getter returns the same singleton bean object, infinite recursion triggers StackOverflowError:
java.lang.StackOverflowError
at org.springframework.beans.BeanWrapperImpl$BeanPropertyHandler.getValue(BeanWrapperImpl.java:270)
at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:623)
at org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.resetProperties(ConfigurationPropertiesRebinder.java:216)
at org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.resetProperties(ConfigurationPropertiesRebinder.java:231)
at org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.resetProperties(ConfigurationPropertiesRebinder.java:231)
... (repeats indefinitely)
Four beans in our project affected: ReloadableLdapProperties (getInstance()), SysConfigProperties (getInstance()), ApiSecurityProperties (getBean()), AppSettings (getBean()).
Spring Cloud mitigated the symptom in 5.0.3 (spring-cloud/spring-cloud-commons#1699) by adding an IdentityHashMap-based cycle guard to resetProperties(). However, the static getter is still incorrectly discovered as a property — the cycle guard only prevents the crash, it doesn't address this root cause.
Expected Behavior
BeanWrapperImpl should NOT discover static methods as bean properties. Static methods do not operate on bean instances and are not part of the JavaBeans property model.
Suggested Fix
In the property discovery logic, filter out getter methods where Modifier.isStatic(method.getModifiers()) returns true.
Workarounds
1. Upgrade to spring-cloud-context 5.0.3+ (cycle guard prevents the crash downstream)
2. Add affected beans to spring.cloud.refresh.never-refreshable
3. Rename static getters to not follow getXxx() pattern (e.g., findInstance())
4. Add -Xss JVM flag to increase thread stack size (masks symptom, does not fix)
Affects: Spring Framework 7.0.8 (regression since 6.0)
Summary
AbstractNestablePropertyAccessor/BeanWrapperImpldiscoverspublic staticgetter methods as JavaBean properties. A@ConfigurationPropertiesclass withpublic static Xxx getInstance()gets a read-only property namedinstancethat returns the singleton object. This is a regression from SpringFramework 5.x where
CachedIntrospectionResultsexplicitly filtered static methods viaModifier.isStatic().Root Cause
Spring Framework 6.0 replaced
java.beans.Introspector-based property discovery with a custom "efficient method reflection pass." This reflection pass no longer checksModifier.isStatic()on discovered getter methods, sopublic staticgetters likegetInstance(),getBean()are registered as beanproperties alongside actual instance properties.
Reproduction