Skip to content

Add jackson benchmarks #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ package dev.zacsweers.jsonserialization.android
import androidx.benchmark.junit4.BenchmarkRule
import androidx.benchmark.junit4.measureRepeated
import androidx.test.filters.LargeTest
import com.fasterxml.jackson.databind.ObjectReader
import com.fasterxml.jackson.databind.ObjectWriter
import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.google.common.base.Charsets
import com.google.common.io.Resources
import com.google.gson.Gson
Expand All @@ -28,11 +32,21 @@ import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import dev.zacsweers.jsonserialization.models.adapter.GeneratedJsonAdapterFactory
import dev.zacsweers.jsonserialization.models.adapter.GeneratedTypeAdapterFactory
import dev.zacsweers.jsonserialization.models.kotlinx_serialization.Response
import dev.zacsweers.jsonserialization.models.jackson.JackResponse
import dev.zacsweers.jsonserialization.models.jacksonKotlin.JKResponse
import dev.zacsweers.jsonserialization.models.java_serialization.ResponseJ
import dev.zacsweers.jsonserialization.models.kotlinx_serialization.Response
import dev.zacsweers.jsonserialization.models.model_av.ResponseAV
import dev.zacsweers.jsonserialization.models.moshiKotlinCodegen.KCGResponse
import dev.zacsweers.jsonserialization.models.moshiKotlinReflective.KRResponse
import java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.io.Reader
import java.io.Writer
import kotlinx.serialization.KSerializer
import okio.Buffer
import okio.BufferedSink
Expand All @@ -42,15 +56,11 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.junit.runners.Parameterized.Parameters
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.io.Reader
import java.io.Writer

@LargeTest
@RunWith(Parameterized::class)
class AndroidBenchmark(
minified: Boolean
minified: Boolean,
) {

companion object {
Expand Down Expand Up @@ -236,6 +246,76 @@ class AndroidBenchmark(
}
}

class JacksonDatabind(json: String) {
private val mapper = JsonMapper()
val reader: ObjectReader
val writer: ObjectWriter
val response: JackResponse

init {
val javaType = mapper.typeFactory.constructType(JackResponse::class.java)
reader = mapper.readerFor(javaType)
writer = mapper.writerFor(javaType)
response = reader.readValue(json, JackResponse::class.java)
}
}

class JacksonDatabindBuffer(private val json: String) {
private val mapper = JsonMapper()
val reader: ObjectReader
val writer: ObjectWriter
val response: JackResponse
lateinit var source: Reader
lateinit var sink: Writer

init {
val javaType = mapper.typeFactory.constructType(JackResponse::class.java)
reader = mapper.readerFor(javaType)
writer = mapper.writerFor(javaType)
response = reader.readValue(json, JackResponse::class.java)
}

fun setupIteration() {
source = InputStreamReader(Buffer().write(json.toByteArray()).inputStream(), Charsets.UTF_8)
sink = OutputStreamWriter(Buffer().outputStream(), Charsets.UTF_8)
}
}

class JacksonKotlinDatabind(json: String) {
private val mapper = jacksonObjectMapper()
val reader: ObjectReader
val writer: ObjectWriter
val response: JKResponse

init {
val javaType = mapper.typeFactory.constructType(JKResponse::class.java)
reader = mapper.readerFor(javaType)
writer = mapper.writerFor(javaType)
response = reader.readValue(json)
}
}

class JacksonKotlinDatabindBuffer(private val json: String) {
private val mapper = jacksonObjectMapper()
val reader: ObjectReader
val writer: ObjectWriter
val response: JKResponse
lateinit var source: Reader
lateinit var sink: Writer

init {
val javaType = mapper.typeFactory.constructType(JKResponse::class.java)
reader = mapper.readerFor(javaType)
writer = mapper.writerFor(javaType)
response = reader.readValue(json)
}

fun setupIteration() {
source = InputStreamReader(Buffer().write(json.toByteArray()).inputStream(), Charsets.UTF_8)
sink = OutputStreamWriter(Buffer().outputStream(), Charsets.UTF_8)
}
}

@get:Rule
val benchmarkRule = BenchmarkRule()
@Suppress("UnstableApiUsage")
Expand Down Expand Up @@ -382,4 +462,56 @@ class AndroidBenchmark(
val param = runWithTimingDisabled { AVGsonBuffer(json).also { it.setupIteration() } }
param.adapter.fromJson(param.source)
}

@Test
fun jackson_string_fromJson() = benchmarkRule.measureRepeated {
val param = runWithTimingDisabled { JacksonDatabind(json) }
param.reader.readValue(json, JackResponse::class.java)
}

@Test
fun jackson_buffer_fromJson() = benchmarkRule.measureRepeated {
val param = runWithTimingDisabled { JacksonDatabindBuffer(json).also { it.setupIteration() } }
param.reader.readValue(param.source, JackResponse::class.java)
}

@Test
fun jackson_string_toJson() = benchmarkRule.measureRepeated {
val param = runWithTimingDisabled { JacksonDatabind(json) }
param.writer.writeValueAsString(param.response)
}

@Test
fun jackson_buffer_toJson() = benchmarkRule.measureRepeated {
val param = runWithTimingDisabled { JacksonDatabindBuffer(json).also { it.setupIteration() } }
param.writer.writeValue(param.sink, param.response)
}

@Test
fun jackson_kotlin_string_fromJson() = benchmarkRule.measureRepeated {
val param = runWithTimingDisabled { JacksonKotlinDatabind(json) }
param.reader.readValue(json, JKResponse::class.java)
}

@Test
fun jackson_kotlin_string_toJson() = benchmarkRule.measureRepeated {
val param = runWithTimingDisabled { JacksonKotlinDatabind(json) }
param.writer.writeValueAsString(param.response)
}

@Test
fun jackson_kotlin_buffer_fromJson() = benchmarkRule.measureRepeated {
val param = runWithTimingDisabled {
JacksonKotlinDatabindBuffer(json).also { it.setupIteration() }
}
param.reader.readValue(param.source, JKResponse::class.java)
}

@Test
fun jackson_kotlin_buffer_toJson() = benchmarkRule.measureRepeated {
val param = runWithTimingDisabled {
JacksonKotlinDatabindBuffer(json).also { it.setupIteration() }
}
param.writer.writeValue(param.sink, param.response)
}
}
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
3 changes: 3 additions & 0 deletions models/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,7 @@ dependencies {
api "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
api "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
api "org.jetbrains.kotlinx:kotlinx-serialization-json:$serialization_version"

api 'com.fasterxml.jackson.core:jackson-databind:2.14.2'
api 'com.fasterxml.jackson.module:jackson-module-kotlin:2.14.2'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package dev.zacsweers.jsonserialization.models.jackson

import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty

data class JackFriend @JsonCreator constructor(
@JsonProperty("id") val id: Int,
@JsonProperty("name") val name: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package dev.zacsweers.jsonserialization.models.jackson

import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty

class JackImage @JsonCreator constructor(
@JsonProperty("id") val id: String,
@JsonProperty("format") val format: String,
@JsonProperty("url") val url: String,
@JsonProperty("description") val description: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package dev.zacsweers.jsonserialization.models.jackson

import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty

class JackName @JsonCreator constructor(
@JsonProperty("first") val first: String,
@JsonProperty("last") val last: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package dev.zacsweers.jsonserialization.models.jackson

import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty

class JackResponse @JsonCreator constructor(
@JsonProperty("users") val users: List<JackUser>,
@JsonProperty("status") val status: String,
@JsonProperty("is_real_json") val isRealJson: Boolean,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package dev.zacsweers.jsonserialization.models.jackson

import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty

data class JackUser @JsonCreator constructor(
@JsonProperty("_id") val id: String,
@JsonProperty("index") val index: Int,
@JsonProperty("guid") val guid: String,
@JsonProperty("is_active") val isActive: Boolean,
@JsonProperty("balance") val balance: String,
@JsonProperty("picture") val pictureUrl: String,
@JsonProperty("age") val age: Int,
@JsonProperty("name") val name: JackName,
@JsonProperty("company") val company: String,
@JsonProperty("email") val email: String,
@JsonProperty("address") val address: String,
@JsonProperty("about") val about: String,
@JsonProperty("registered") val registered: String,
@JsonProperty("latitude") val latitude: Double,
@JsonProperty("longitude") val longitude: Double,
@JsonProperty("tags") val tags: List<String>,
@JsonProperty("range") val range: List<Int>,
@JsonProperty("friends") val friends: List<JackFriend>,
@JsonProperty("images") val images: List<JackImage>,
@JsonProperty("greeting") val greeting: String,
@JsonProperty("favorite_fruit") val favoriteFruit: String,
@JsonProperty("eye_color") val eyeColor: String,
@JsonProperty("phone") val phone: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package dev.zacsweers.jsonserialization.models.jacksonKotlin

data class JKFriend(
val id: Int,
val name: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package dev.zacsweers.jsonserialization.models.jacksonKotlin

class JKImage(
val id: String,
val format: String,
val url: String,
val description: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package dev.zacsweers.jsonserialization.models.jacksonKotlin

class JKName(
val first: String,
val last: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package dev.zacsweers.jsonserialization.models.jacksonKotlin

import com.fasterxml.jackson.annotation.JsonProperty

class JKResponse(
val users: List<JKUser>,
val status: String,
@JsonProperty("is_real_json")
val isRealJson: Boolean
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package dev.zacsweers.jsonserialization.models.jacksonKotlin

import com.fasterxml.jackson.annotation.JsonProperty

data class JKUser(
@JsonProperty("_id")
val id: String,
val index: Int,
val guid: String,
@JsonProperty("is_active")
val isActive: Boolean,
val balance: String,
@JsonProperty("picture")
val pictureUrl: String,
val age: Int,
val name: JKName,
val company: String,
val email: String,
val address: String,
val about: String,
val registered: String,
val latitude: Double,
val longitude: Double,
val tags: List<String>,
val range: List<Int>,
val friends: List<JKFriend>,
val images: List<JKImage>,
val greeting: String,
@JsonProperty("favorite_fruit")
val favoriteFruit: String,
@JsonProperty("eye_color")
val eyeColor: String,
val phone: String
)