baomidou/mybatis-plus · error · UnsupportedOperationException

不支持的方法!

Error message

不支持的方法!

What it means

IRepository.removeById(Serializable id, boolean useFill) defaults to throwing UnsupportedOperationException('不支持的方法!' — 'Unsupported method!'). The base IRepository interface only implements the common path; the fill-aware variant (which converts the id to an entity to run fill logic before delete) is only meaningful for implementations backed by a full ServiceImpl-style repository. Calling it on the default interface, or on a custom implementation that does not override it, explodes.

Source

Thrown at mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/repository/IRepository.java:74

    /**
     * 根据 ID 删除
     *
     * @param id 主键ID
     */
    default boolean removeById(Serializable id) {
        return SqlHelper.retBool(getBaseMapper().deleteById(id));
    }

    /**
     * 根据 ID 删除
     *
     * @param id      主键(类型必须与实体类型字段保持一致)
     * @param useFill 是否启用填充(为true的情况,会将入参转换实体进行delete删除)
     * @return 删除结果
     * @since 3.5.0
     */
    default boolean removeById(Serializable id, boolean useFill) {
        throw new UnsupportedOperationException("不支持的方法!");
    }

    /**
     * 根据实体(ID)删除
     *
     * @param entity 实体
     * @since 3.4.4
     */
    default boolean removeById(T entity) {
        return SqlHelper.retBool(getBaseMapper().deleteById(entity));
    }

    /**
     * 根据 columnMap 条件,删除记录
     *
     * @param columnMap 表字段 map 对象
     */
    default boolean removeByMap(Map<String, Object> columnMap) {

View on GitHub (pinned to bf67d90747)

Solutions

  1. Override removeById(Serializable id, boolean useFill) in your IRepository implementation, implementing the fill path (convert id to entity, apply meta-object fill, delete).
  2. Or call the supported variant removeById(id) (single-argument) which routes to getBaseMapper().deleteById(id) directly.
  3. If fill-on-delete is required, extend the provided ServiceImpl/repository base class that already implements it.
  4. In tests, use Mockito with CALLS_REAL_METHODS awareness or explicitly stub the two-argument variant.

Example fix

// before: custom repo does not override fill variant
public class UserRepository implements IRepository<User> {
    // removeById(id, useFill) inherited default -> UnsupportedOperationException
}

// after: override it
public class UserRepository implements IRepository<User> {
    @Override
    public boolean removeById(Serializable id, boolean useFill) {
        if (!useFill) return SqlHelper.retBool(getBaseMapper().deleteById(id));
        User entity = getById(id);
        return SqlHelper.retBool(getBaseMapper().deleteById(entity));
    }
}
Defensive patterns

Strategy: type-guard

Validate before calling

IRepository<User> repo = acquireRepository();
boolean fillVariantSupported;
try {
    repo.getClass().getMethod("removeById", Serializable.class, boolean.class)
        .getDeclaringClass();
    fillVariantSupported = !IRepository.class.equals(
        repo.getClass().getMethod("removeById", Serializable.class, boolean.class).getDeclaringClass());
} catch (NoSuchMethodException e) { fillVariantSupported = false; }
if (!fillVariantSupported) repo.removeById(id); // use supported single-arg variant

Type guard

static boolean supportsRemoveByIdWithFill(Object repo) {
    try {
        Method m = repo.getClass().getMethod("removeById", Serializable.class, boolean.class);
        return !m.getDeclaringClass().isInterface(); // real override, not default
    } catch (NoSuchMethodException e) {
        return false;
    }
}

Try / catch

try {
    repository.removeById(id, true);
} catch (UnsupportedOperationException e) {
    repository.removeById(id); // fall back to the always-supported variant
}

Prevention

When it happens

Trigger: Holding an IRepository (or a custom implementation of it) and calling removeById(id, true) — the two-argument fill variant — without the concrete class overriding that default method. Introduced in 3.5.0; implementations like the standard repository/service impl override it, minimal custom ones do not.

Common situations: Custom IRepository implementations (e.g. a thin repository over a base mapper) written against an older API surface, then new code calls the 3.5.0 fill variant; switching a bean from ServiceImpl to a hand-written repository loses the override; mocking IRepository in tests without stubbing the default method (some mock libs invoke real defaults).


AI-assisted analysis of baomidou/mybatis-plus@bf67d90747 (2026-08-14). Data as JSON: /api/errors/24551a3e68fc1e65. Report an issue: GitHub.