Files
amethyst/commons
Claude e7d3bcdc01 perf: drop jackson-module-kotlin, removing kotlin-reflect from the app
Nothing in the app binds JSON reflectively any more, so the module whose whole
job is reflective Kotlin binding has no work left to do. Swapping it for plain
jackson-databind takes kotlin-reflect out with it:

    kotlin.reflect.jvm.internal          969 -> 0 classes
    com.fasterxml.jackson.module.kotlin   73 -> 0 classes
    DEX                              30.94 MB -> 29.94 MB, 3 files -> 2

A megabyte and a whole secondary DEX, for code the app never called.

`jacksonObjectMapper()` became `ObjectMapper()` in all eight remaining places:
JacksonMapper and JsonMapperNip55 (both drive registered StdSerializer /
StdDeserializer pairs) and six readTree-only users (LNURL resolvers, TorService,
ArtiGuardState, Nip96Uploader). None of them needed the Kotlin module.

The one thing the module did that databind has no equivalent for is
`jacksonTypeRef<T>()`, which NIP-55 needs: `readValue<List<IntentResult>>` erases
to `List` under `T::class.java` and every element comes back a LinkedHashMap. It
is a one-liner — `reified` substitutes the concrete type into the anonymous
subclass before erasure — so it now lives in quartz as jacksonTypeRefOf().

quartz exported the module as an `api` dependency, so test sources three modules
away were quietly using it. Those move over too, same two swaps: `ObjectMapper()`
where the mapper only walks maps or readTree (the pretty-printer test, the BIP-39
vectors, the event-command benchmark, quic's qlog writer and its test), and
`jacksonTypeRefOf<ArrayList<Event>>()` where the reified `readValue<T>` extension
was doing the typeref's job (LargeDBSignatureCheck, the thread-order test, the
two cache benchmarks). Event's own deserializer is registered on the mapper, so
databind resolves it either way.

`cli` keeps the module. It genuinely binds its config files reflectively
(Config, OperatorKeys, Aliases, StatusReport), it declares the dependency itself,
and it is never minified, so none of this applies there. desktopApp, geode,
relayBench and quic-interop likewise declare it directly and are unaffected.

Verified: `./gradlew test` green, the instrumented sources compile
(:quartz:compileAndroidDeviceTestSources, :amethyst and :benchmark androidTest),
R8 release build green, 19/19 contract checks, and both package prefixes
confirmed at zero classes in the shipped DEX.

Note for whoever hits it next: a full recompile of :amethyst needs more than a
2 GB Kotlin daemon. Mine died with "Couldn't transform method node" pointing at a
Compose lambda in NoteCompose.kt, which is an OutOfMemoryError in the ASM frame
analyzer wearing a disguise, not a code fault.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEoxktEZyTrAS33vVZBiwm
2026-09-19 14:01:07 +00:00
..