spring-projects/spring-framework · error · UnsupportedOperationException

Unexpected MethodOverride subclass:

Error message

Unexpected MethodOverride subclass: 

What it means

Thrown as an UnsupportedOperationException during AOT code generation when a bean definition contains a MethodOverride that is neither a LookupOverride nor a ReplaceOverride. The generator (addMethodOverrides) only knows how to emit code for those two built-in subclasses; any other subclass (custom or from a newer Spring version) is rejected because there is no codegen path for it.

Solutions

  1. Identify the MethodOverride subclass named in the message and either remove it from the bean definition or replace it with LookupOverride/ReplaceOverride.
  2. Resolve version skew: align spring-beans and spring-context (and any Spring-dependent libs) to the same Spring version so no new override type is unhandled.
  3. If you own the override, refactor to use @Lookup or a MethodReplacer-based ReplaceOverride so the built-in codegen covers it.
  4. Exclude the affected bean from AOT processing if it cannot be expressed with the supported override types.
  5. Open an issue / contribute an AOT codegen branch in BeanDefinitionPropertiesCodeGenerator for the new override type.

Example fix

// before: custom MethodOverride subclass the AOT generator can't emit
beanDefinition.getMethodOverrides().addOverride(myCustomOverride);

// after: use a supported ReplaceOverride
beanDefinition.getMethodOverrides()
    .addOverride(new ReplaceOverride("doWork", "workerReplacer"));
Defensive patterns

Strategy: validation

Validate before calling

// Reject unsupported MethodOverride subclasses before AOT
for (MethodOverride o : beanDefinition.getMethodOverrides().getOverrides()) {
    if (!(o instanceof LookupOverride) && !(o instanceof ReplaceOverride)) {
        throw new IllegalStateException(
            "Unsupported MethodOverride: " + o.getClass().getName());
    }
}

Type guard

// Narrow to supported override types
boolean supported = override instanceof LookupOverride || override instanceof ReplaceOverride;

Prevention

When it happens

Trigger: A RootBeanDefinition has a MethodOverrides set containing an instance of a third-party or custom MethodOverride subclass, or a Spring core MethodOverride added in a newer version that this codegen branch does not handle. Triggered while BeanDefinitionPropertiesCodeGenerator.addMethodOverrides iterates the overrides.

Common situations: Library/framework that programmatically adds a custom MethodOverride to bean definitions; upgrading Spring core to a version that introduces a new MethodOverride type while keeping an older spring-beans (version skew); XML configuration using a custom method-replacer that surfaces as an unknown override shape.

Related errors


AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09). Data as JSON: /api/errors/6642fe31a2a0a0dd. Report an issue: GitHub.

Appendix: 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 69bf83ad71)