Commit Graph

2 Commits

Author SHA1 Message Date
m 31e73e3865 fix(desktop): add ProGuard keep rules for reflection-heavy deps
The v1.09.1 desktop release (DMG/MSI/DEB/RPM) fails to launch on every
platform with:

  Exception in thread "main" java.lang.ExceptionInInitializerError
      at com.fasterxml.jackson.databind.ObjectMapper.<init>(ObjectMapper.java:700)
      at com.vitorpamplona.amethyst.desktop.ui.deck.DeckState.<clinit>
  Caused by: java.lang.NullPointerException:
      Cannot read the array length because the return value of
      "java.lang.Class.getEnumConstants()" is null
      at com.fasterxml.jackson.databind.cfg.MapperConfig
              .collectFeatureDefaults(MapperConfig.java:107)
  Failed to launch JVM

Root cause: PR #2914 wired Compose 1.11.0's new ProGuard pass into the
release build but added only `-dontwarn` rules. ProGuard then optimized
Jackson's enum classes (`SerializationFeature`, `MapperFeature`, etc.) and
stripped their synthetic `values()` / `valueOf()` methods because nothing
in Amethyst's own bytecode calls them. Jackson does call them — but
reflectively, at `ObjectMapper` construction time, long after ProGuard
finished. The result is `Class.getEnumConstants()` returning null and the
JVM giving up.

The same regression silently broke VLC media playback (VLCj's
`ServiceLoader` lookup of `DiscoveryDirectoryProvider` impls printed
`ConfigDirConfigFileDiscoveryDirectoryProvider not found` because
ProGuard stripped both the META-INF/services file and the impl class).

Fix: add explicit `-keep` rules for the four reflection-heavy libraries
on the desktop classpath:

- Jackson (databind, core, annotations, module-kotlin): keep classes
  intact and keep `values()`/`valueOf()` on every Jackson enum.
- JNA (com.sun.jna.\*\*): used by VLCj and kmp-tor — its `Structure`
  field-order reflection requires field metadata to survive.
- VLCj (uk.co.caprica.vlcj.\*\*): `ServiceLoader`-based discovery providers
  and reflective binding classes throughout.
- SLF4J: detected by Jackson via `Class.forName`.

Verified by building `:desktopApp:createReleaseDistributable` and
launching the resulting bundle on macOS arm64:
  - No `ExceptionInInitializerError`
  - `VLC: bundled discovery succeeded`
  - `VLC: MediaPlayerFactory created successfully`

The same ProGuard pass runs on all four target formats (Dmg, Msi, Deb,
Rpm) so this single change fixes the regression on every desktop OS.
2026-05-16 09:13:56 +10:00
Claude ffd64a2e70 fix(desktop): add project ProGuard rules to unblock release packaging
Compose Multiplatform 1.11.0 tightened its default ProGuard ruleset so
`proguardReleaseJars` now fails on unresolved references that 1.10.3
tolerated silently. The v1.09.0 release tag-build hit this on every
desktop leg (macOS DMG, Windows MSI, Linux DEB/RPM, Linux AppImage),
which is why only Android APKs and the macOS-arm64 / Linux Amy CLI
bundles made it onto the GitHub release.

Three groups of references were flagged:

  - Jackson kotlin-module 2.21.x value-class converters
    (`IntValueClassBoxConverter`, `ValueClassKeyDeserializer$*`, …)
    invoke `MethodHandle.invokeExact` with polymorphic signatures
    ProGuard cannot resolve against the abstract MethodHandle.
  - okhttp's optional TLS adapters (`okhttp3.internal.graal.*`,
    `BouncyCastle/Conscrypt/OpenJSSEPlatform`) reference classes from
    runtime backends that aren't on the desktop classpath; okhttp falls
    back to the JDK default in their absence.
  - JNA's `com.sun.jna.internal.Cleaner` inner classes touch synthetic
    `access$N` accessors that ProGuard's class-member analysis cannot
    follow.

Add `desktopApp/compose-rules.pro` with `-dontwarn` rules for each
bucket and wire it through `compose.desktop.application.buildTypes
.release.proguard.configurationFiles`. Verified locally by re-running
`:desktopApp:proguardReleaseJars` (now BUILD SUCCESSFUL) and
`:desktopApp:packageReleaseDeb` (gets past ProGuard; only fails on the
sandbox missing `fakeroot`, which CI installs in the existing
"Install RPM tooling" step).
2026-05-15 21:03:28 +00:00