Skip to content

Conversation

yet300
Copy link
Contributor

@yet300 yet300 commented Sep 30, 2025

Description

This PR migrates the entire Bitchat Android codebase from using Android's Parcelize and Google's Gson to Kotlin's native kotlinx.serialization library. This modernization brings significant benefits in terms of performance, type safety, and future-proofing.

🚀 Why This Migration?

Current Pain Points

  • Reflection overhead: Gson uses heavy reflection at runtime, impacting performance
  • Runtime errors: Type mismatches and serialization issues only discovered at runtime
  • APK bloat: Gson adds significant binary size due to reflection metadata
  • Maintenance burden: Two different serialization systems (Parcelize for Android, Gson for JSON)
  • Limited multiplatform support: Gson is JVM-only, limiting future Kotlin Multiplatform adoption

Benefits of kotlinx.serialization

  • Compile-time safety: All serialization code generated at compile time
  • Better performance: No reflection overhead, faster serialization/deserialization
  • Smaller APK: Reduced binary size without reflection metadata
  • Unified approach: Single serialization system for all data formats
  • Multiplatform ready: Native Kotlin solution works across all platforms
  • Modern ecosystem: Official JetBrains library with active development

🔧 Technical Changes

Dependencies Updated

// Removed
implementation("com.google.code.gson:gson:2.13.1")
id("kotlin-parcelize")

// Added  
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0")
id("org.jetbrains.kotlin.plugin.serialization")

Custom Serializers Created

  • DateSerializer: Handles java.util.Date using milliseconds since epoch
  • ByteArraySerializer: Handles ByteArray using Base64 encoding
  • UByteSerializer & ULongSerializer: Handle unsigned integer types
  • JsonUtil: Centralized JSON operations replacing Gson usage

Files Migrated

Model Classes (Parcelize → @serializable)

  • BitchatMessage + DeliveryStatus enum
  • IdentityAnnouncement
  • NoisePayload, PrivateMessagePacket, ReadReceipt
  • BitchatPacket with binary protocol support

Nostr Protocol Classes (Gson → kotlinx.serialization)

  • NostrEvent with @SerialName field mapping
  • NostrRequest with custom JSON array serialization
  • NostrFilter with tag filter support
  • NostrResponse with updated parsing logic

Service Classes

  • SeenMessageStore: Message deduplication storage
  • GeohashBookmarksStore: Location channel bookmarks
  • LocationChannelManager: Channel data persistence
  • FavoritesPersistenceService: Complex nested data structures
  • DataManager: Application preferences
  • NoiseChannelEncryption: Encrypted channel packets

📱 Impact Assessment

Positive Impacts

  • Performance: Faster app startup and JSON operations
  • Reliability: Compile-time error detection prevents runtime crashes
  • Maintainability: Single, modern serialization approach
  • Future-proofing: Ready for Kotlin Multiplatform expansion
  • Developer experience: Better IDE support and debugging

Risk Mitigation

  • Gradual rollout: Can be feature-flagged if needed
  • Rollback plan: Previous Gson implementation preserved in git history
  • Monitoring: Performance metrics tracked post-deployment
  • Testing: Comprehensive test coverage ensures compatibility

🔍 Code Quality Improvements

  • Type Safety: Eliminated Map<String, Any> usage with proper data classes
  • Null Safety: Better null handling with kotlinx.serialization's optional fields
  • Performance: Removed reflection-based serialization bottlenecks
  • Consistency: Unified serialization approach across entire codebase

Checklist

  • Remove Gson and Parcelize dependencies
  • Add kotlinx.serialization dependencies
  • Create custom serializers for Date, ByteArray, UByte, ULong
  • Migrate all @Parcelize classes to @Serializable
  • Replace all Gson usage with JsonUtil
  • Update Nostr protocol JSON handling
  • Migrate service layer persistence
  • Update build configuration
  • Verify all tests pass
  • Performance testing completed

actions-user and others added 14 commits September 21, 2025 06:21
Replaced `Parcelable` with `kotlinx.serialization.Serializable` across data models to improve serialization performance and maintainability.

- Replaced the `kotlin-parcelize` plugin with `kotlin-serialization`.
- Added `kotlinx-serialization-json` dependency.
- Updated `IdentityAnnouncement`, `BitchatMessage`, `BitchatPacket`, `NoisePayload`, `PrivateMessagePacket`, and `ReadReceipt` to use `@Serializable`.
- Introduced a new `Serializers.kt` file with custom serializers for `Date`, `ByteArray`, `UByte`, and `ULong` to ensure compatibility.
Introduces `JsonUtil`, a Kotlin object that serves as a wrapper around the `kotlinx.serialization` library.

This utility provides methods for serializing objects to JSON and deserializing JSON strings to objects, including safe versions that return null on error. It is configured to be lenient and ignore unknown keys.
Replaced Gson with `kotlinx.serialization` for JSON handling across the application. This improves performance and ensures better integration with Kotlin.

- Updated `NostrEvent`, `NostrFilter`, `BitchatMessage`, `IdentityAnnouncement`, `BitchatPacket`, and `SeenMessageStore` data classes to use `@Serializable`.
- Replaced `@SerializedName` with `@SerialName`.
- Created custom `ByteArraySerializer`, `UByteSerializer`, and `ULongSerializer` for handling specific types in `BitchatPacket` and `IdentityAnnouncement`.
- Introduced a `JsonUtil` helper to centralize serialization logic.
- Removed the Gson dependency and related imports.
- Refactored `NostrFilter` to move helper functions and the `Builder` class into a companion object.
This commit replaces the Gson library with kotlinx.serialization for all JSON processing related to Nostr messages (requests, responses, and protocol operations).

Key changes include:
- Removing custom `JsonSerializer` implementations.
- Updating `NostrRequest.toJson` to use `buildJsonArray` from kotlinx.serialization.
- Modifying `NostrResponse.fromJsonArray` and other parsing logic to use kotlinx.serialization's `JsonElement` API instead of Gson's.
- Removing the Gson instance from `NostrRelayManager` and `NostrProtocol`.
Replaced Gson with kotlinx.serialization for `NoisePayload` and `NoiseChannelEncryption`.

This change introduces a custom `ByteArraySerializer` to handle the serialization of the `data` field in `NoisePayload` and updates the channel key packet processing to use the new JSON utility.
Replaced all instances of the Gson library with the `kotlinx.serialization` library for JSON handling.

- Introduced a new `JsonUtil` helper class for serialization and deserialization.
- Updated `GeohashBookmarksStore`, `LocationChannelManager`, `FavoritesPersistenceService`, and `DataManager` to use `JsonUtil`.
- Added the `@Serializable` annotation to `FavoriteRelationshipData`.
- Ensured safer JSON parsing by handling potential nulls and exceptions during deserialization.
The Gson JSON library is no longer in use and has been removed from the project's dependencies.
@callebtc
Copy link
Collaborator

Thank you, great addition. I will review this.

@callebtc callebtc added enhancement New feature or request needs review Someone should look at it labels Oct 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request needs review Someone should look at it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants