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.
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).