Mongo BSON support for kotlinx.serialization.

Overview

Maven Central Bintray

kbson

What is this?

This adapter adds BSON support to kotlinx.serialization.

BSON types supported:

  • Double
  • String
  • Array
  • Binary
  • UUID
  • ObjectId
  • Boolean
  • Date
  • Symbol
  • 32-bit integer
  • Long
  • Decimal128

Install

build.gradle.kts

dependencies {
    // kotlin 1.3
    implementation("com.github.jershell:kbson:0.3.0")
    // kotlin 1.4.20 & kotlinx.serialization 1.0.1
    implementation("com.github.jershell:kbson:0.4.4")
}

or

build.gradle

dependencies {
    // kotlin 1.3
    implementation 'com.github.jershell:kbson:0.3.0'
    // kotlin 1.4.20 & kotlinx.serialization 1.0.1
    implementation 'com.github.jershell:kbson:0.4.4'
}

Usage samples

Parsing from BSON to a Kotlin object
import kotlinx.serialization.Serializable
import com.github.jershell.kbson.ObjectIdSerializer

val kBson = KBson()


@Serializable
data class Simple (
        val valueString: String,

        val valueDouble: Double,

        val valueFloat: Float,

        val valueLong: Long,

        val valueChar: Char,

        val valueBool: Boolean,

        @NonEncodeNull
        @ContextualSerialization
        val _id: ObjectId? = null,

        @ContextualSerialization
        val uuid: UUID,

        val valueInt: Int
)

val simple = kBson.parse(Simple.serializer(), bsonDocFromMongoJavaDriver)
Serializing from a Kotlin object to BSON
import kotlinx.serialization.Serializable
import com.github.jershell.kbson.Configuration
import com.github.jershell.kbson.KBson
import com.github.jershell.kbson.ObjectIdSerializer

@Serializable
data class Simple (
        val valueString: String = "default",
        val valueDouble: Double,
        val valueFloat: Float,
        val valueLong: Long,
        val valueChar: Char,
        val valueBool: Boolean,
        @NonEncodeNull
        @ContextualSerialization 
        val _id: ObjectId? = null,
        val valueInt: Int
)

// Optional configuration
val kBson = KBson(Configuration(encodeDefaults = false))
val bsonDoc = kBson.stringify(Simple.serializer(), simpleModel)

// You can override default serializers or add your serializer  
val kBson = KBson(context = serializersModuleOf(mapOf(
            ObjectId::class to ObjectIdSerializer,
            Date::class to DateSerializer
    )))
    
// You can use load and dump with ByteArray 
val simple = kBson.load(Simple.serializer(), bsonDoc)
// also
val simple2 = kBson.load(Simple.serializer(), bsonDoc.toByteArray())
// !!!! The method load() use BsonDecoder and strict order of fields

See the tests for more examples

API

val kBson = KBson()

kBson.parse(deserializer: DeserializationStrategy<T>, doc: BsonDocument) :T
// !!!! The method load() use BsonDecoder and strict order of fields
// https://docs.mongodb.com/manual/tutorial/update-documents/#field-order
kBson.load(deserializer: DeserializationStrategy<T>, doc: ByteArray): T
kBson.load(deserializer: DeserializationStrategy<T>, doc: BsonDocument): T

kBson.stringify(): BsonDocument
kBson.dump(serializer: SerializationStrategy<T>, obj: T): ByteArray

// Extension functions 
BsonDocument.toByteArray(): ByteArray
BsonDocument.toDocument(): Document

Configuration

classDiscriminator = "___type" // name of the class descriptor property in polymorphic serialization.
encodeDefaults = "true" // specifies whether default values are encoded.
ps

@NonEncodeNull useful for item _id mongodb

The default enum class supported like string. You can also override it

kbson before 0.1.5 use kotlinx.serialization 0.11.x

kbson after 0.1.5 use kotlinx.serialization 0.13.x

kbson after 0.2.0 use kotlinx.serialization 0.14.x

kbson after 0.2.2 use kotlinx.serialization 0.20.0 and kotlin 1.3.71

kbson after 0.4.0 use kotlinx.serialization "1.0-M1-1.4.0-rc" and kotlin 1.4.0-rc

kbson after 0.4.1 use kotlinx.serialization "1.0.0" and kotlin 1.4.10

kbson after 0.4.3 use kotlinx.serialization "1.0.0" and kotlin 1.4.20

Contributing to kbson

Pull requests and bug reports are always welcome!

To run the tests: ./gradlew check

Reference links

Comments
  • Use BsonReader & BsonWriter

    Use BsonReader & BsonWriter

    Hello,

    Trying to implement a first version of org.bson.codecs.Codec ( https://github.com/Litote/kmongo/commit/8b03c1343ddcbbcfce6c551c09d446bdbe426751#diff-43a261a5b319c5b393c2428d036ce9f4R39 ), I hit a first issue.

    encode & decode methods of Codec use BsonWriter & BsonReader but kbson takes BsonDocumentWriter & BsonDocument

    Is it doable to change Encoder and Decoder input type?

    Thank you

    opened by zigzago 6
  • Kotlin 1.4

    Kotlin 1.4

    Hello! Thank you for your project. Now Kotlin 1.4.0 Release Candidate is available and kotlin-serialization contains a lot of breaking changes.

    For example, I have this issue:

    java.lang.NoClassDefFoundError: kotlinx/serialization/PrimitiveKind$STRING
    	at com.github.jershell.kbson.ObjectIdSerializer.<clinit>(Serializers.kt:115)
    
    WIP 
    opened by petersamokhin 5
  • Default constructor error

    Default constructor error

    Hi there --

    Thanks for the lib.

    I'm using kbson inside kMongo. That part works great.

    Trying to use kbson to manually serialize/deserialize doesn't work, though. I can't even instantiate the class.

    java.lang.NoSuchMethodError: com.github.jershell.kbson.Configuration.<init>(ZLjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
    
    	at com.github.jershell.kbson.KBson.<init>(KBson.kt:12)
    	at com.github.jershell.kbson.KBson.<clinit>(KBson.kt:41)
    

    Not sure what to do here, honestly.

    opened by abiessener 5
  • Polymorphism is not supported

    Polymorphism is not supported

    I get this stacktrace when I try to serialize a inherited class (as described here https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md )

    java.lang.ClassCastException: kotlinx.serialization.UnionKind$POLYMORPHIC cannot be cast to kotlinx.serialization.StructureKind

    at com.github.jershell.kbson.BsonEncoder.beginStructure(BsonEncoder.kt:28)
    at kotlinx.serialization.PolymorphicSerializer.serialize(Polymorphic.kt:87)
    
    opened by zigzago 4
  • Problem while trying to write to KMongo

    Problem while trying to write to KMongo

    Hi,

    I am new to Kotlin and its ecosystem, so I don't know if this bug is related to this repository or KMongo (or kotlix.serialization).

    There is a minimal repro here.

    The problem is following:

    I have the following data class which is in a file I cannot edit:

    data class User(
        val username: String,
        val email: String,
        val firstName: String,
        val lastName: String,
        val password: String,
        val role: Role,
        val createdAt: LocalDateTime,
        val updatedAt: LocalDateTime
    )
    

    So, in my file I create a serializer for it like this:

    @Serializer(forClass = User::class)
    object UserSerializer {}
    

    Now, everything seems to work OK when deserializing the data, however when KMongo tries to serialize it and send it to DB, I get a nasty java exception stack with the following message:

    Exception in thread "main" java.lang.IndexOutOfBoundsException: User descriptor has only 8 elements, index: 0

    • at kotlinx.serialization.internal.PluginGeneratedSerialDescriptor.getElementDescriptor(PluginGeneratedSerialDescriptor.kt:62)
    • at com.github.jershell.kbson.BsonEncoder.encodeElement(BsonEncoder.kt:109)
    • ...

    After going through code, I found that in file PluginGeneratedSerialDescriptor.kt there is an overriden fun getElementDescriptor in which property generatedSerializer is trying to get accessed, but it is null and this causes the exception.

    Does anyone know if this is a bug, or I'm doing something wrong here? If it has nothing do to with this repository, sorry for bothering you, I'll ask in kotlinx.serialization.

    Thanks!

    opened by ivan-brko 3
  • add flexible decoder

    add flexible decoder

    I benchmark kbson for bson deserialization performance (in order to add kotlinx.serialization to this page: http://litote.org/kmongo/performance/ )

    During my tests, I found that BsonDocumentDecoder suffers from a x5/x10 performance penalty compared to BsonDecoder.

    So this PR adds a "FlexibleDecoder" that has the same features than BsonDocumentDecoder and the same speed than BsonDecoder. :)

    It contains also small changes linked to kotlinx.serialization upgrade from 0.13 to 0.14

    opened by zigzago 2
  • Parse raw JsonObject with kotlinx serialization

    Parse raw JsonObject with kotlinx serialization

    I'm unable to parse raw json using KMongo with kotlinx serialization

    @Serializable
    data classPersonInInDB(
        var _id: String? = null,
        @Contextual val updatedAt: Date,
        var value: kotlinx.serialization.json.JsonObject,
    )
    
    java.lang.IllegalStateException: This serializer can be used only with Json format.Expected Decoder to be JsonDecoder, got class com.github.jershell.kbson.BsonFlexibleDecoder
    	at kotlinx.serialization.json.JsonElementSerializersKt.asJsonDecoder(JsonElementSerializers.kt:201)
    	at kotlinx.serialization.json.JsonElementSerializersKt.verify(JsonElementSerializers.kt:197)
    	at kotlinx.serialization.json.JsonElementSerializersKt.access$verify(JsonElementSerializers.kt:1)
    	at kotlinx.serialization.json.JsonObjectSerializer.deserialize(JsonElementSerializers.kt:161)
    	at kotlinx.serialization.json.JsonObjectSerializer.deserialize(JsonElementSerializers.kt:144)
    	at kotlinx.serialization.encoding.Decoder$DefaultImpls.decodeSerializableValue(Decoding.kt:257)
    	at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableValue(AbstractDecoder.kt:16)
    	at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableValue(AbstractDecoder.kt:43)
    	at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableElement(AbstractDecoder.kt:70)
    

    Is it even possible?

    opened by omkar-tenkale 1
  • writeString can only be called when State is VALUE, not when State is NAME

    writeString can only be called when State is VALUE, not when State is NAME

    When trying to serialize this class a strange exception is thrown:

    writeString can only be called when State is VALUE, not when State is NAME
    org.bson.BsonInvalidOperationException: writeString can only be called when State is VALUE, not when State is NAME
    	at org.bson.AbstractBsonWriter.throwInvalidState(AbstractBsonWriter.java:746)
    	at org.bson.AbstractBsonWriter.checkPreconditions(AbstractBsonWriter.java:701)
    	at org.bson.AbstractBsonWriter.writeString(AbstractBsonWriter.java:606)
    	at com.github.jershell.kbson.BsonEncoder.encodeEnum(BsonEncoder.kt:139)
    	at kotlinx.serialization.internal.EnumSerializer.serialize(Enums.kt:70)
    	at kotlinx.serialization.internal.EnumSerializer.serialize(Enums.kt:52)
    	at kotlinx.serialization.Encoder$DefaultImpls.encodeSerializableValue(Encoding.kt:252)
    	at kotlinx.serialization.builtins.AbstractEncoder.encodeSerializableValue(AbstractEncoder.kt:16)
    	at kotlinx.serialization.builtins.AbstractEncoder.encodeSerializableElement(AbstractEncoder.kt:72)
    	at kotlinx.serialization.internal.MapLikeSerializer.serialize(CollectionSerializers.kt:131)
    	at kotlinx.serialization.Encoder$DefaultImpls.encodeSerializableValue(Encoding.kt:252)
    	at kotlinx.serialization.builtins.AbstractEncoder.encodeSerializableValue(AbstractEncoder.kt:16)
    	at kotlinx.serialization.builtins.AbstractEncoder.encodeSerializableElement(AbstractEncoder.kt:72)
    	at ...
    

    It seems that the internal state of the serializer is compromised when writing some elements. Also it happens only on enums.

    opened by lamba92 1
  • Set serialization is not supported

    Set serialization is not supported

    See a test case here: https://github.com/Litote/kmongo/blob/master/kmongo-serialization-mapping/src/test/kotlin/SerializationCodecTest.kt#L64

    And the stacktrace:

    
    java.lang.IllegalArgumentException: Size must be known in advance when using READ_ALL
    
    	at kotlinx.serialization.internal.ListLikeSerializer.readAll(CollectionSerializers.kt:83)
    	at kotlinx.serialization.internal.AbstractCollectionSerializer.patch(CollectionSerializers.kt:35)
    	at kotlinx.serialization.internal.AbstractCollectionSerializer.deserialize(CollectionSerializers.kt:49)
    	at com.github.jershell.kbson.BsonDocumentDecoder.decodeSerializableValue(BsonDocumentDecoder.kt:46)
    	at kotlinx.serialization.TaggedDecoder$decodeSerializableElement$1.invoke(Tagged.kt:245)
    	at kotlinx.serialization.TaggedDecoder.tagBlock(Tagged.kt:258)
    	at kotlinx.serialization.TaggedDecoder.decodeSerializableElement(Tagged.kt:245)
    
    opened by zigzago 1
  • Map with object key is not supported

    Map with object key is not supported

    See https://github.com/Litote/kmongo/blob/master/kmongo-serialization-mapping/src/test/kotlin/SerializationCodecTest.kt#L78 for a test sample.

    The stacktrace:

    kotlinx.serialization.SerializationException: map key name is not primitive
    
    	at com.github.jershell.kbson.BsonEncoder.encodeElement(BsonEncoder.kt:97)
    	at kotlinx.serialization.ElementValueEncoder.encodeSerializableElement(ElementWise.kt:82)
    	at kotlinx.serialization.internal.MapLikeSerializer.serialize(CollectionSerializers.kt:133)
    
    opened by zigzago 1
  • Deserialization failure for polymorphic (or sealed) classes

    Deserialization failure for polymorphic (or sealed) classes

    with this bson:

    {"_id":ObjectId(5d17ab793b4083d41f829821),"___type": "int-value", "value": 1}

    and this class:

    
    @Serializable
    sealed class Value
    
    @Serializable
    @SerialName("int-value")
    data class IntValue(val value: Int) : Value()
    

    there is a failure during deserialization. This is because PolymorphismDecoder should use decodeSequentially at false and its decodeElementIndex should be updated to not infer that the discriminator property is always first.

    I'm going to propose on a fix ;)

    bug 
    opened by zigzago 0
  • Add support to encode Json in BsonEncoder

    Add support to encode Json in BsonEncoder

    Some times it is required to serialise in Bson a property that is mapped to a Map<String, Any?> type. It would be nice if the Map<String, Any?> can be encoded to a Json structure. This can be easily done by adding one method in BsonReader to encode a JSON string

    fun encodeJson(value: String) {
            when (state) {
                STATE.VALUE -> writer.pipe(JsonReader(value))
                STATE.NAME -> throw SerializationException("Json is not supported as a key of map")
            }
    }
    

    I created a patch that add this method. There is also a test case KBsonMapAnyTest.kt that you can check and understand better why this method is needed.

    add_support_to_encode_Json_structure.txt

    It will be also nice if there was a decoder from BsonDocument to Map<String, Any?>. I tried to use BsonFlexibleDecoder but maybe there is a better way to do it. You can check parseBsonDocument inside MapAnySerializer object in the test classes.

    opened by ageorgousakis 0
  • Type check should be a little more relaxed

    Type check should be a little more relaxed

    I have an object with a Long property, but the value is stored as Double. When I try to deserialize it:

    org.bson.BsonInvalidOperationException: Value expected to be of type INT64 is of unexpected type DOUBLE
    
    	at org.bson.BsonValue.throwIfInvalidType(BsonValue.java:419)
    	at org.bson.BsonValue.asInt64(BsonValue.java:105)
    	at com.github.jershell.kbson.BsonDocumentDecoder.decodeTaggedLong(BsonDocumentDecoder.kt:198)
    	at com.github.jershell.kbson.BsonDocumentDecoder.decodeTaggedLong(BsonDocumentDecoder.kt:30)
    	at kotlinx.serialization.TaggedDecoder.decodeLongElement(Tagged.kt:238)
    

    It would be a nice addition to cast the value when it is doable

    enhancement help wanted 
    opened by zigzago 1
Owner
jershell
jershell
Android Parcelable support for the Kotlinx Serialization library.

Android Parcelable support for the Kotlinx Serialization library.

Christopher 50 Nov 20, 2022
CSV and FixedLength Formats for kotlinx-serialization

Module kotlinx-serialization-csv Serialize and deserialize ordered CSV and Fixed Length Format Files with kotlinx-serialization. Source code Docs Inst

Philip Wedemann 12 Dec 16, 2022
Kotlin tooling for generating kotlinx.serialization serializers for serializing a class as a bitmask

kotlinx-serialization-bitmask Kotlin tooling for generating kotlinx.serialization serializers for serializing a class as a bitmask. Example @Serializa

marie 2 May 29, 2022
Type-safe arguments for JetPack Navigation Compose using Kotlinx.Serialization

Navigation Compose Typed Compile-time type-safe arguments for JetPack Navigation Compose library. Based on KotlinX.Serialization. Major features: Comp

Kiwi.com 32 Jan 4, 2023
KotlinX Serialization Standard Serializers (KS3)

KotlinX Serialization Standard Serializers (KS3) This project aims to provide a set of serializers for common types. ⚠️ Consider this project to be Al

Emil Kantis 3 Nov 5, 2022
A tiny Kotlin multiplatform library that assists in saving and restoring objects to and from disk using kotlinx.coroutines, kotlinx.serialisation and okio

Store A tiny Kotlin multiplatform library that assists in saving and restoring objects to and from disk using kotlinx.coroutines, kotlinx.serialisatio

Isuru Rajapakse 98 Jan 3, 2023
Create an application with Kotlin/JVM and Kotlin/JS, and explore features around code sharing, serialization, server- and client

Practical Kotlin Multiplatform on the Web 본 저장소는 코틀린 멀티플랫폼 기반 웹 프로그래밍 워크숍(강좌)을 위해 작성된 템플릿 프로젝트가 있는 곳입니다. 워크숍 과정에서 코틀린 멀티플랫폼을 기반으로 프론트엔드(front-end)는 Ko

SpringRunner 14 Nov 5, 2022
Create an application with Kotlin/JVM and Kotlin/JS, and explore features around code sharing, serialization, server- and client

Building a Full Stack Web App with Kotlin Multiplatform 본 저장소는 INFCON 2022에서 코틀린 멀티플랫폼 기반 웹 프로그래밍 핸즈온랩을 위해 작성된 템플릿 프로젝트가 있는 곳입니다. 핸즈온 과정에서 코틀린 멀티플랫폼을

Arawn Park 19 Sep 8, 2022
Automatic CoroutineDispatcher injection and extensions for kotlinx.coroutines

Dispatch Utilities for kotlinx.coroutines which make them type-safe, easier to test, and more expressive. Use the predefined types and factories or de

Rick Busarow 132 Dec 9, 2022
Small Kafka Playground to play around with Test Containers, and KotlinX Coroutines bindings while reading Kafka Definite Guide V2

KafkaPlayground Small playground where I'm playing around with Kafka in Kotlin and the Kafka SDK whilst reading the Kafka book Definite Guide from Con

Simon Vergauwen 34 Dec 30, 2022
An tool to help developer to use Retrofit elegantly while using kotlinx.coroutines.

one An tool to help developer to use Retrofit elegantly while using kotlinx.coroutines. Feature Transform different data structs to one. {errorCode, d

ChengTao 30 Dec 27, 2022
Kotlinx-murmurhash - Kotlin Multiplatform (KMP) library for hashing using MurmurHash

kotlinx-murmurhash Kotlin Multiplatform (KMP) library for MurmurHash, a non-cryp

Gonçalo Silva 23 Dec 27, 2022
Cross-platform framework for building truly native mobile apps with Java or Kotlin. Write Once Run Anywhere support for iOS, Android, Desktop & Web.

Codename One - Cross Platform Native Apps with Java or Kotlin Codename One is a mobile first cross platform environment for Java and Kotlin developers

Codename One 1.4k Jan 9, 2023
A Kotlin work manager library for Android with progress notifications and Hilt support.

Boot Laces A kotlin work manager library for Android that includes notifications and Hilt support. User Instructions Add the JitPack repository to you

Chris Basinger 35 Oct 8, 2022
Template (pure) for KMM application with DI support

KMM di template Template (pure) for KMM application with DI support. Uses Multiplatform-DI for Dependency Injection Features Common architecture (VIP)

Anna Zharkova 8 Oct 18, 2022
Dependency Injection library for Kotlin Multiplatform, support iOS and Android

Multiplatform-DI library for Kotlin Multiplatform Lightweight dependency injection framework for Kotlin Multiplatform application Dependency injection

Anna Zharkova 32 Nov 10, 2022
Wrapper of FusedLocationProviderClient for Android to support modern usage like LiveData and Flow

FancyLocationProvider Wrapper of FusedLocationProviderClient for Android to support modern usage like LiveData or Flow. Install Add Jitpack repository

Jintin 66 Aug 15, 2022
Kotlin multiplatform decorators support

DEKORATOR [WIP] Decorator support for Kotlin! Built with ❤ , powered by Kotlin compiler plugin. Support The plugin only works on targets using new IR

Martynas Petuška 3 Mar 18, 2022
A simple, classic Kotlin MVI implementation based on coroutines with Android support, clean DSL and easy to understand logic

A simple, classic Kotlin MVI implementation based on coroutines with Android support, clean DSL and easy to understand logic

Nek.12 4 Oct 31, 2022