pagehelper-org/Mybatis-PageHelper · critical · PageException

Failed to get the BoundSql property additionalParameters

Error message

Failed to get the BoundSql property additionalParameters: ${e}

What it means

ExecutorUtil uses reflection to access the private field BoundSql.additionalParameters, which MyBatis does not expose via a public API in older versions. During class initialization it looks up this field; if the loaded mybatis jar's BoundSql class does not declare it (incompatible/very new or shaded mybatis version), the static initializer throws this PageException and the class fails to load.

Solutions

  1. Align versions: use a pagehelper release compatible with your mybatis version (check pagehelper's documented mybatis compatibility matrix)
  2. Run mvn dependency:tree (or gradle dependencies) and remove duplicate/conflicting mybatis jars so only one expected version is on the classpath
  3. Downgrade/upgrade mybatis to a version whose BoundSql declares additionalParameters
  4. Upgrade pagehelper to the latest release, which supports newer mybatis APIs
  5. If truly blocked, report to pagehelper issues — newer pagehelper versions avoid this reflection via mybatis's own accessors

Example fix

// before (pom.xml)
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.99</version></dependency>
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.4</version></dependency>

// after (compatible pair)
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.9</version></dependency>
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.3.2</version></dependency>
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify compatibility at startup before relying on pagination
try {
    Class.forName("com.github.pagehelper.util.ExecutorUtil");
} catch (Throwable t) {
    throw new IllegalStateException("PageHelper incompatible with loaded mybatis BoundSql: " + t, t);
}

Try / catch

try (SqlSession session = factory.openSession()) {
    return mapper.selectPaged(params);
} catch (PageException e) {
    if (e.getMessage().contains("additionalParameters")) {
        throw new IllegalStateException("mybatis/pagehelper version mismatch — align versions", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Application startup when the ExecutorUtil class is first loaded against a mybatis version whose BoundSql class lacks the 'additionalParameters' field — e.g. a major mybatis upgrade, a shaded/repackaged mybatis, or mismatched pagehelper/mybatis dependency versions.

Common situations: Upgrading MyBatis past the version PageHelper was built for; duplicate mybatis jars on the classpath where the wrong one wins; OSGi/shaded deployments hiding the field.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

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

import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * @author liuzenghui
 */
public abstract class ExecutorUtil {

    private static Field additionalParametersField;

    private static Field providerMethodArgumentNamesField;

    static {
        try {
            additionalParametersField = BoundSql.class.getDeclaredField("additionalParameters");
            additionalParametersField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            throw new PageException("Failed to get the BoundSql property additionalParameters: " + e, e);
        }
        try {
            //兼容低版本
            providerMethodArgumentNamesField = ProviderSqlSource.class.getDeclaredField("providerMethodArgumentNames");
            providerMethodArgumentNamesField.setAccessible(true);
        } catch (NoSuchFieldException ignore) {
        }
    }

    /**
     * 获取 BoundSql 属性值 additionalParameters
     *
     * @param boundSql
     * @return
     */
    public static Map<String, Object> getAdditionalParameter(BoundSql boundSql) {
        try {
            return (Map<String, Object>) additionalParametersField.get(boundSql);

View on GitHub (pinned to c692616c5b)