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

  1. Call setExecutorWrapper() on the delegate executor, not on the CachingExecutor wrapper
  2. If walking an executor chain, unwrap via getDelegate() (or check instanceof CachingExecutor first) before calling wrapper-related methods
  3. 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

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


AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14). Data as JSON: /api/errors/573c0c0b645b3852. Report an issue: GitHub.