Subject: [pgjdbc/pgjdbc] PR #4069: Avoid direct java.lang.management dependency in maxResultBuffer parser

From: "mblakley-casana (@mblakley-casana)" <[email-masked]>
Date: Wed, 13 May 2026 21:03:28 +0000

Fixes #4068

### All Submissions:

* [x] Have you followed the guidelines in our [Contributing](https://github.com/pgjdbc/pgjdbc/blob/master/CONTRIBUTING.md) document?
* [x] Have you checked to ensure there aren't other open [Pull Requests](../../pulls) for the same update/change?

I checked for existing issues/PRs with `ManagementFactory`, `java.lang.management`, `Android`, and `PGPropertyMaxResultBufferParser` and did not find a matching open PR.

<!-- You can erase any parts of this template not applicable to your Pull Request. -->

### Changes to Existing Features:

* [x] Does this break existing behaviour? If so please explain.

No. On Java SE runtimes where `java.lang.management` is available, percentage values are still calculated from max heap and large explicit byte values are still capped to 90% of max heap.

On runtimes without `java.lang.management`, behavior changes only for the heap-introspection paths:

- unset `maxResultBuffer` remains disabled
- explicit byte values are accepted as provided
- percentage values fail with a `PSQLException` explaining that percentage values require `java.lang.management.ManagementFactory`

* [x] Have you added an explanation of what your changes do and why you'd like us to include them?

Android's ART runtime does not include the Java SE `java.lang.management` package. Because `PGPropertyMaxResultBufferParser` directly references `ManagementFactory`, Android can fail class resolution while loading the driver class graph, even when `maxResultBuffer` is unset and the percentage-based syntax is not used.

The management API is only needed to compute percentage values like `10pct` and to cap explicit byte sizes to 90% of max heap. This change removes the verifier-visible `java.lang.management.ManagementFactory` reference and resolves `ManagementFactory`, `MemoryMXBean`, and `MemoryUsage` reflectively only when max-heap introspection is needed.

* [x] Have you written new tests for your core changes, as applicable?

Yes. `PGPropertyMaxResultBufferParserRuntimeTest` covers a runtime where the management classes cannot be resolved:

- unset value parses as disabled
- explicit byte value parses
- percentage value throws `PSQLException`
- max heap lookup reports unavailable

* [x] Have you successfully run tests with your changes locally?

Yes:

```text
./gradlew :postgresql:styleCheck
./gradlew :postgresql:test --tests org.postgresql.test.util.PGPropertyMaxResultBufferParserTest --tests org.postgresql.util.PGPropertyMaxResultBufferParserRuntimeTest
./gradlew -PenableErrorprone -PenableCheckerframework :postgresql:classes
git diff --check
```

I also validated the patched driver on Android API 34:

- published the local patched driver as `org.postgresql:postgresql:42.7.12-SNAPSHOT`
- substituted it into an Android instrumentation test runtime
- loaded `org.postgresql.Driver`
- reached `org.postgresql.jdbc.PgConnection`
- executed a simple JDBC query successfully

The Android instrumentation result was `OK (1 test)`.

I attempted the targeted pgjdbc tests with `-PjdkTestVersion=8`, but this local machine does not have a Java 8 toolchain configured and Gradle toolchain download repositories are not configured, so that run could not start. CI should cover the supported JDK matrix.

---

From: "vlsi (@vlsi)" <[email-masked]>
Date: Mon, 18 May 2026 06:50:43 +0000

@mblakley-casana , could you please try an alternative approach I pushed on the branch? Does it work for your Android case?
I would like to avoid adding reflection-based code as it is hard to maintain.

---

From: "mblakley-casana (@mblakley-casana)" <[email-masked]>
Date: Mon, 18 May 2026 12:16:20 +0000

Tested two layers:

JVM (simulated) — re-ran the existing JUnit tests against your commit:

```
./gradlew :postgresql:test \
    --tests org.postgresql.test.util.PGPropertyMaxResultBufferParserTest \
    --tests org.postgresql.util.PGPropertyMaxResultBufferParserRuntimeTest
PGPropertyMaxResultBufferParserRuntimeTest: 3 tests, 0 failures (your refactored LongSupplier-based reproducer)
PGPropertyMaxResultBufferParserTest: 11 tests, 0 failures
```

Real Android (API 34, AVD Medium_Phone_API_34) — built your commit locally as 42.7.12-SNAPSHOT, consumed from mavenLocal in an Android instrumentation test:

```
@RunWith(AndroidJUnit4::class)
class PgjdbcAndroidSmokeTest {
    @Test
    fun pgjdbcDriverLoadsAndParsesMaxResultBuffer() {
        Class.forName("org.postgresql.Driver")
        assertEquals(1000L, PGPropertyMaxResultBufferParser.parseProperty("1K"))
        assertThrows(PSQLException::class.java) {
            PGPropertyMaxResultBufferParser.parseProperty("10pct")
        }
    }
}
```

`tests=1 failures=0 errors=0 in 12 ms.`

Driver class graph resolves cleanly on ART — keeping JvmHeapAccess referenced from PGPropertyMaxResultBufferParser does not trigger eager verification of java.lang.management.ManagementFactory.
The byte path (1K) never touches the holder.
The percent path (10pct) loads JvmHeapAccess, ART fails to link it (no ManagementFactory), the catch (LinkageError) returns -1, and the parser raises PSQLException.

I like your solution, and verified that it will work on Android.  Thank you!