Skip to content

Object Mapping Performance

Bson deserialization is a key factor to measure performance of KMongo, as usually you retrieve more data from MongoDB than you send to the db.

Complete deserialization

The benchmark sources are available in github.

We take a Bson representation of this class:

data class FriendWithBuddies(
     val _id: ObjectId? = null,
     val name: String? = null,
     val address: String? = null,
     val coordinate: Coordinate? = null,
     val gender: Gender? = null,
     val buddies: List<FriendWithBuddies> = emptyList()
 )

And deserialize it using:

  • org.bson.Document (driverFriend)
  • Jackson mapping (jacksonFriend)
  • Native/POJO mapping (nativeFriend)
  • kotlinx.Serialization (serializationFriend)

Measured with jmh:

Simple benchmark

As you can see, the org.bson.Document mapping (basically a Map) outperforms Jackson & Native mapping but kotlinx.Serialization is the best - this is expected: no reflection is involved for kotlinx.Serialization.

Note: during this benchmark, we have found a ~15% perf improvement for jackson but the fix is not included in the last released version of bson4jackson. However, even with this improvement, the ranking stays the same.

Is it possible to improve Jackson & native mapping performance? Of course! You can write a custom Jackson deserializer or a custom codec for the FriendWithBuddies class. Then you avoid reflection in both case, and you speed up your deserialization.

Then we get these results:

Benchmark with custom deserializer/codec

We can see that jackson is better now, but it is "Native" mapping that really shines. However, writing a custom deserializer or codec is cumbersome and error prone. For Jackson, there is a small library that generates automatically the deserializers for the class annotated with @JacksonData. Here is the result:

Benchmark with @JacksonData

The custom deserializer version performs better, but you get a 40% improvement "for free" with @JacksonData.

Partial deserialization

Now we take the same Bson than before, but we deserialize it in a partial object: a friend without its buddies.

data class Friend(
     val _id: ObjectId? = null,
     val name: String? = null,
     val address: String? = null,
     val coordinate: Coordinate? = null,
     val gender: Gender? = null
 )

Here are the results:

Friend benchmark

kotlinx.Serialization outperforms everything. This is because kotlinx.Serialization mapping (like native mapping that has also a signifiant boost) skips the not mapped bson data, when org.bson.Document & Bson4Jackson parse the bson entirely.

Conclusion

If performance is critical for your use case, use "kotlinx.Serialization" mapping. But "Native" and Jackson does not perform that bad, and are also valid choices for almost all projects.