spring-projects/spring-framework · error · UnsupportedOperationException

Unexpected MethodOverride subclass: {}

Error message

Unexpected MethodOverride subclass: {}

What it means

BeanDefinitionPropertiesCodeGenerator emits AOT code for method overrides but only knows how to handle LookupOverride and ReplaceOverride. Any other MethodOverride subclass hits an UnsupportedOperationException, since the generator has no code-emission strategy for it.

Source

Thrown at spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java:303

					arguments.add(CodeBlock.of("$S", lookupOverride.getMethodName()));
					arguments.add(CodeBlock.of("$S", lookupOverride.getBeanName()));
					code.addStatement("$L.getMethodOverrides().addOverride(new $T($L))", BEAN_DEFINITION_VARIABLE,
							LookupOverride.class, CodeBlock.join(arguments, ", "));
				}
				else if (methodOverride instanceof ReplaceOverride replaceOverride) {
					Collection<CodeBlock> arguments = new ArrayList<>();
					arguments.add(CodeBlock.of("$S", replaceOverride.getMethodName()));
					arguments.add(CodeBlock.of("$S", replaceOverride.getMethodReplacerBeanName()));
					List<String> typeIdentifiers = replaceOverride.getTypeIdentifiers();
					if (!typeIdentifiers.isEmpty()) {
						arguments.add(CodeBlock.of("java.util.List.of($S)",
								StringUtils.collectionToDelimitedString(typeIdentifiers, ", ")));
					}
					code.addStatement("$L.getMethodOverrides().addOverride(new $T($L))", BEAN_DEFINITION_VARIABLE,
							ReplaceOverride.class, CodeBlock.join(arguments, ", "));
				}
				else {
					throw new UnsupportedOperationException("Unexpected MethodOverride subclass: " +
							methodOverride.getClass().getName());
				}
			}
		}
	}

	private CodeBlock generateValue(@Nullable String name, @Nullable Object value) {
		PropertyNamesStack.push(name);
		try {
			return this.valueCodeGenerator.generateCode(value);
		}
		finally {
			PropertyNamesStack.pop();
		}
	}

	private Class<?> getInfrastructureType(RootBeanDefinition beanDefinition) {
		if (beanDefinition.hasBeanClass()) {

View on GitHub (pinned to e8729d0438)

Solutions

  1. Replace the custom MethodOverride subclass with LookupOverride or ReplaceOverride if the semantics allow.
  2. If you maintain the custom override, contribute a dedicated AOT code generator/hook for it upstream or avoid AOT for that bean.
  3. Fall back to JIT (non-AOT) runtime if the custom override is mandatory.

Example fix

// before
beanDef.getMethodOverrides().addOverride(new MyCustomOverride("foo"));
// after
beanDef.getMethodOverrides().addOverride(new LookupOverride("foo", "replacementBean"));
Defensive patterns

Strategy: type-guard

Validate before calling

for (MethodOverride o : beanDefinition.getMethodOverrides()) {
  if (!(o instanceof LookupOverride || o instanceof ReplaceOverride)) {
    throw new IllegalStateException("Unsupported override type for AOT: " + o.getClass());
  }
}

Type guard

boolean aotSupportedOverride(MethodOverride o) {
  return o instanceof LookupOverride || o instanceof ReplaceOverride;
}

Prevention

When it happens

Trigger: A bean definition carries a custom subclass of org.springframework.beans.factory.support.MethodOverride that is neither LookupOverride nor ReplaceOverride during AOT code generation.

Common situations: A library or framework registers a bespoke MethodOverride type; programmatic bean definitions that instantiate a MethodOverride subclass directly. This is essentially an internal framework limitation surfacing during native-image/AOT builds.

Related errors


AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04). Data as JSON: /data/errors/b7c4463354060f36.json. Report an issue: GitHub.