pagehelper-org/Mybatis-PageHelper · error · PageException

Get the ProviderSqlSource property value of…

Error message

Get the ProviderSqlSource property value of providerMethodArgumentNames: ${e}

What it means

ExecutorUtil reflectively reads ProviderSqlSource.providerMethodArgumentNames to support @SelectProvider methods; the field only exists in some mybatis versions (absence is tolerated at init). If the field exists but Field.get fails with IllegalAccessException (accessibility revoked, module restrictions, SecurityManager), the helper throws this PageException.

Solutions

  1. Upgrade pagehelper to a release matching your mybatis version so the reflection path (or its replacement API) works
  2. Add JVM opens for the mybatis package: --add-opens org.mybatis/java.org.apache.ibatis.builder.annotation=ALL-UNNAMED
  3. Adjust the SecurityManager policy to grant ReflectPermission("suppressAccessChecks") to the application
  4. Replace the @SelectProvider usage with XML or annotation SQL if compatibility cannot be fixed, avoiding this code path
  5. Deduplicate mybatis on the classpath (dependency:tree) so the standard class is loaded

Example fix

// before (JVM args)
java -jar app.jar

// after
java --add-opens org.mybatis/java.org.apache.ibatis.builder.annotation=ALL-UNNAMED -jar app.jar
Defensive patterns

Strategy: try-catch

Validate before calling

// Probe accessibility of the provider field before using @SelectProvider + pagination
java.lang.reflect.Field f = null;
try {
    f = org.apache.ibatis.builder.annotation.ProviderSqlSource.class.getDeclaredField("providerMethodArgumentNames");
    f.setAccessible(true);
    f.get(null);
} catch (NoSuchFieldException ignore) {
    // tolerated: mybatis version without this field
} catch (Throwable t) {
    throw new IllegalStateException("Cannot access ProviderSqlSource internals: " + t, t);
}

Try / catch

try {
    return mapper.selectPaged(params);
} catch (PageException e) {
    if (e.getMessage().contains("providerMethodArgumentNames")) {
        throw new IllegalStateException("Open mybatis module packages or upgrade pagehelper/mybatis", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Paginating a mapper method whose SQL comes from @SelectProvider (ProviderSqlSource) in an environment where the reflected field is not accessible: JPMS strong encapsulation, SecurityManager denying suppressAccessChecks, or a shaded/repackaged mybatis where setAccessible silently did not apply.

Common situations: Annotation-based mappers using provider classes on JDK 16+ with module encapsulation; enterprise app servers with strict security policies; mixed mybatis versions after dependency conflicts.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of pagehelper-org/Mybatis-PageHelper@c692616c5b (2026-09-08). Data as JSON: /api/errors/f6a642c13a35405d. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/com/github/pagehelper/util/ExecutorUtil.java:92

    public static Map<String, Object> getAdditionalParameter(BoundSql boundSql) {
        try {
            return (Map<String, Object>) additionalParametersField.get(boundSql);
        } catch (IllegalAccessException e) {
            throw new PageException("Failed to get the BoundSql property additionalParameters: " + e, e);
        }
    }

    /**
     * 获取 ProviderSqlSource 属性值 providerMethodArgumentNames
     *
     * @param providerSqlSource
     * @return
     */
    public static String[] getProviderMethodArgumentNames(ProviderSqlSource providerSqlSource) {
        try {
            return providerMethodArgumentNamesField != null ? (String[]) providerMethodArgumentNamesField.get(providerSqlSource) : null;
        } catch (IllegalAccessException e) {
            throw new PageException("Get the ProviderSqlSource property value of providerMethodArgumentNames: " + e, e);
        }
    }

    /**
     * 尝试获取已经存在的在 MS,提供对手写count和page的支持
     *
     * @param configuration
     * @param msId
     * @return
     */
    public static MappedStatement getExistedMappedStatement(Configuration configuration, String msId) {
        MappedStatement mappedStatement = null;
        try {
            mappedStatement = configuration.getMappedStatement(msId, false);
        } catch (Throwable t) {
            //ignore
        }
        return mappedStatement;

View on GitHub (pinned to c692616c5b)