Tag Archives: Android

Kotlin Bites Code

Disclosure: AI-assisted content — consult with an organic-developer.

When building low-level libraries for the JVM — especially those that interact with JNI, rendering engines, or MethodHandles — the exact bytecode emitted matters. Recently I hit a limitation in Kotlin that reminded me why the JVM world still needs Java for certain things.


Where Kotlin Emits Different Bytecode than Java

Here are the main areas where Kotlin’s generated bytecode diverges from Java’s, and why that matters.

AreaJavaKotlinTakeaway
Signature-polymorphic callsEmits correct signature for MethodHandle.invokeExactFalls back to (Object[])Object, causing mismatchesKeep these calls in Java
Default parametersNo defaults → use overloadsGenerates synthetic $default methods with bitmaskAvoid defaults in public APIs for Java clients
Companion objects / @JvmStaticTrue static methodsMethods live in $Companion unless annotatedUse @JvmStatic or plain Java for static APIs
Internal visibilityPackage-private supportedinternal compiles to public + metadataDon’t rely on internal for cross-language encapsulation
SAM interfacesAny functional interface = lambdaOnly fun interface supports SAM; lambdas may create synthetic classesDefine callbacks in Java for performance
NullabilityAll references nullableAnnotations encode nullability, JVM doesn’t enforceExplicit null checks needed in low-level code
Suspend functions / coroutinesN/ACompiles to (Arg, Continuation) → ObjectKeep coroutines in Kotlin wrappers, not core API

Other Kotlin Caveats for Low-Level Code

This wasn’t an isolated issue. Kotlin differs from Java in other ways that make it risky for core interop code:

AreaJavaKotlin limitation
JNI declarationsstatic native boolean render(int, int)Needs @JvmStatic in a companion object; generates synthetic names
JNI header generationjavac -h works directlyNo header generation for Kotlin sources
Checked exceptionsEnforced at compile-timeKotlin ignores them (all unchecked)
Raw typesAllowed (List)Always requires generics (List<*>)
Wildcards? super? extends supportedOnly in / out; cannot express everything
Default paramsNot supported (overloads instead)Compiles to synthetic $default methods
Static membersstatic keywordRequires @JvmStatic in object/companion
Suspend functionsN/ACompiled to Continuation-based state machines, awkward for Java callers

Why This Matters for Library Code

A low-level library often deals with:

  • JNI ↔ JVM bridges
  • OpenGL or native rendering loops
  • Performance-critical calls that must inline
  • Reflection and MethodHandles

All of these require predictable bytecode and signatures. Kotlin often inserts synthetic classes ($Companion$DefaultImpls$WhenMappings) or adapts signatures in ways Java clients (and JNI) do not expect.


Why Keeping the Library Core in Java Makes Sense

BenefitWhy It Matters
One language to maintainSingle codebase, easier contributor onboarding, faster builds
Interop for everyoneJava APIs work in all JVM languages; Kotlin clients lose nothing; Java clients stay safe from Kotlin-only features
JNI friendlinessDirect mapping of Java types to JNI (int → jintboolean → jboolean); javac -h header generation works; avoids $Companion/$DefaultImpls surprises
Bytecode predictabilityNo synthetic baggage ($Companion$default$WhenMappings); avoids mismatched signatures; JIT optimizes exactly as written

Strategy: Java Core + Optional Kotlin API

The pattern I adopted (and which many frameworks use):

  • Core in Java
    • Predictable bytecode
    • JNI header generation
    • Works with MethodHandleVarHandleUnsafe
    • Safe for both Java and Kotlin clients
  • Optional Kotlin extensions (-ktx)
    • Extension functions for ergonomics
    • Coroutines (suspend wrappers)
    • Null-safety
    • DSLs for configuration

This is the same model Android Jetpack follows:
androidx.core in Java, androidx.core-ktx in Kotlin.


Takeaways

PointWhy
MethodHandle supportJava compiler emits exact signatures ((int,int)boolean), Kotlin falls back to (Object[])Object, causing runtime issues
Bytecode predictabilityJava produces direct, predictable bytecode; Kotlin adds synthetic constructs and indirections
JNI compatibilityJava maps directly to JNI types and header generation; Kotlin introduces complications
Best practiceKeep the core in Java for stability and performance; add Kotlin wrappers for ergonomics (DSLs, coroutines, null-safety)

interesting link: https://www.okoone.com/spark/technology-innovation/why-kotlin-swift-and-ruby-are-dropping-off-the-radar/

References

  1. Java SE Docs — MethodHandle and signature-polymorphic methods
    https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/MethodHandle.html
  2. OpenJDK Wiki — Deconstructing MethodHandles
    https://wiki.openjdk.org/display/HotSpot/Deconstructing%2BMethodHandles
  3. Kotlin Docs — Functions and default arguments
    https://kotlinlang.org/docs/functions.html
  4. Medium — Kotlin Function Parameters and Default Values: Behind the Scenes
    https://medium.com/@AlexanderObregon/kotlin-function-parameters-and-default-values-behind-the-scenes-6551fa515fa1
  5. Kotlin Forum — Kotlin bytecode on default parameters
    https://discuss.kotlinlang.org/t/kotlin-bytecode-on-default-parameters/6159
  6. Kotlin Docs — Visibility modifiers (internal, etc.)
    https://www.digitalocean.com/community/tutorials/kotlin-visibility-modifiers-public-protected-internal-private
  7. YouTrack — KT-14416: Support of @PolymorphicSignature in Kotlin compiler
    https://youtrack.jetbrains.com/issue/KT-14416
  8. Baeldung — The @JvmStatic Annotation in Kotlin
    https://www.baeldung.com/kotlin/jvmstatic-annotation
  9. StackOverflow — How to call a static JNI function from Kotlin?
    https://stackoverflow.com/questions/57117201/how-to-call-a-static-jni-function-from-kotlin
  10. The golden age of Kotlin and its uncertain future https://shiftmag.dev/kotlin-vs-java-2392/

Mapy CUZK mobile app available

pikto_100“Mapy CUZK” has been just released on both Android and iOS platforms by “CUZK”( “Czech Office For Surveying, Mapping and Cadastre”). The app enables to see various map compositions from OGC services, perform query and search in the map. it is based the  same engine that powers iKatastr2, enables flexible extensions and uses modern myVR rendering engine.

Apple App Store : https://itunes.apple.com/us/app/mapy-cuzk/id634374870?mt=8

Google Play :  https://play.google.com/store/apps/details?id=com.intergraph.cadaster