{"record":{"id":"573c0c0b645b3852","repo":"mybatis/mybatis-3","slug":"this-method-should-not-be-called","errorCode":null,"errorMessage":"This method should not be called","messagePattern":"This method should not be called","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/executor/CachingExecutor.java","lineNumber":177,"sourceCode":"      Class<?> targetType) {\n    delegate.deferLoad(ms, resultObject, property, key, targetType);\n  }\n\n  @Override\n  public void clearLocalCache() {\n    delegate.clearLocalCache();\n  }\n\n  private void flushCacheIfRequired(MappedStatement ms) {\n    Cache cache = ms.getCache();\n    if (cache != null && ms.isFlushCacheRequired()) {\n      tcm.clear(cache);\n    }\n  }\n\n  @Override\n  public void setExecutorWrapper(Executor executor) {\n    throw new UnsupportedOperationException(\"This method should not be called\");\n  }\n\n}\n","sourceCodeStart":159,"sourceCodeEnd":181,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/executor/CachingExecutor.java#L159-L181","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nExecutor cached = new CachingExecutor(simple);\ncached.setExecutorWrapper(cached); // UnsupportedOperationException\n\n// after\nsimple.setExecutorWrapper(cached); // set wrapper on the delegate","handlingStrategy":"validation","validationCode":"// before invoking wrapper plumbing on an executor chain\nif (executor instanceof CachingExecutor caching) {\n  Executor delegate = caching.getDelegate();\n  delegate.setExecutorWrapper(wrapper); // set on delegate, not decorator\n} else {\n  executor.setExecutorWrapper(wrapper);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["executor","decorator","programming-error"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}