mybatis/mybatis-3 · error · UnsupportedOperationException
This method should not be called
Error message
This method should not be called
What it means
CachingExecutor is a decorator that wraps another Executor to add second-level cache support. The Executor interface declares setExecutorWrapper, but the decorator intentionally does not implement it because only the innermost (delegate) executor should have its wrapper pointer set. Calling it on the decorator is a programming error, so it throws UnsupportedOperationException.
Source
Thrown at src/main/java/org/apache/ibatis/executor/CachingExecutor.java:177
Class<?> targetType) {
delegate.deferLoad(ms, resultObject, property, key, targetType);
}
@Override
public void clearLocalCache() {
delegate.clearLocalCache();
}
private void flushCacheIfRequired(MappedStatement ms) {
Cache cache = ms.getCache();
if (cache != null && ms.isFlushCacheRequired()) {
tcm.clear(cache);
}
}
@Override
public void setExecutorWrapper(Executor executor) {
throw new UnsupportedOperationException("This method should not be called");
}
}
View on GitHub (pinned to 008069adb1)
Solutions
- Call setExecutorWrapper() on the delegate executor, not on the CachingExecutor wrapper
- If walking an executor chain, unwrap via getDelegate() (or check instanceof CachingExecutor first) before calling wrapper-related methods
- Avoid invoking lifecycle/mutating methods on decorator instances; treat CachingExecutor as transparent
Example fix
// before Executor cached = new CachingExecutor(simple); cached.setExecutorWrapper(cached); // UnsupportedOperationException // after simple.setExecutorWrapper(cached); // set wrapper on the delegate
Defensive patterns
Strategy: validation
Validate before calling
// before invoking wrapper plumbing on an executor chain
if (executor instanceof CachingExecutor caching) {
Executor delegate = caching.getDelegate();
delegate.setExecutorWrapper(wrapper); // set on delegate, not decorator
} else {
executor.setExecutorWrapper(wrapper);
} Prevention
- Treat CachingExecutor as a transparent decorator: only call mutating Executor methods on the delegate
- In custom executor wrappers, propagate setExecutorWrapper to the delegate rather than implementing it locally
When it happens
Trigger: Manually creating a CachingExecutor (e.g. new CachingExecutor(delegate)) and then calling setExecutorWrapper() on it; or reflection-based code / mocks that invoke setExecutorWrapper on an executor that happens to be a CachingExecutor. MyBatis core itself calls setExecutorWrapper on the delegate BEFORE wrapping, so normal configuration never triggers this.
Common situations: Custom Executor decorators or plugin code that walks an executor chain and calls every Executor method on each link; unit tests that pass a CachingExecutor where a raw executor is expected.
Related errors
- Executor was closed.
- Could not instantiate cache decorator ({}). Cause: {}
- Invalid cache decorator ({}). Cache decorators must have a
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/573c0c0b645b3852.
Report an issue: GitHub.