Skip to content

Instantly share code, notes, and snippets.

@uzimith
Last active December 11, 2018 00:55
Show Gist options
  • Save uzimith/3fe179f563b14862968b825df0770ef2 to your computer and use it in GitHub Desktop.
Save uzimith/3fe179f563b14862968b825df0770ef2 to your computer and use it in GitHub Desktop.
shapeless vs circe vs refrection
package bench
import org.openjdk.jmh.annotations._
import impl.Impl._
@BenchmarkMode(Array(Mode.Throughput))
@Warmup(iterations = 40, time = 3)
@Measurement(iterations = 40, time = 3)
@Fork(1)
class Bench {
@Benchmark
def benchNoBottleneck(): Unit = {
noBottleneck()
}
@Benchmark
def benchReflection(): Unit = {
reflection()
}
@Benchmark
def benchShapeless(): Unit = {
shapeless()
}
@Benchmark
def benchShapelessAny(): Unit = {
shapelessAny()
}
@Benchmark
def benchCirce(): Unit = {
circe()
}
@Benchmark
def benchJackson(): Unit = {
jackson()
}
}
package impl
import shapeless._
import shapeless.labelled._
import shapeless.record._
import shapeless.ops.record._
import shapeless.syntax.singleton._
import io.circe._
import io.circe.syntax._
import io.circe.generic.auto._
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
case class User(name: String, age: Int)
object Func {
def toJSONString(elem: Any): String = elem match {
case elem: Int => s"${elem}"
case elem: String => s""""${elem}""""
}
}
object toJSONStringPoly extends Poly1 {
implicit def atInt[K] =
at[FieldType[K, Int]](elem => field[K](s"${elem}"))
implicit def atString[K] =
at[FieldType[K, String]](elem => field[K](s""""${elem}""""))
}
object Impl {
val user = User("scalaちゃん", 18)
def reflection(): Unit = {
val fields = user.getClass.getDeclaredFields.map(_.getName)
val values = user.productIterator.toList.map(Func.toJSONString)
val json = fields
.zip(values)
.map {
case (field, value) => s""""${field}":${value}"""
}
.mkString("{", ",", "}")
}
def shapeless(): Unit = {
val userGen = LabelledGeneric[User]
val fields: List[String] =
Keys[userGen.Repr].apply.toList[Symbol].map(_.name)
val values = userGen
.to(user)
.map(toJSONStringPoly)
.toList
val json = fields
.zip(values)
.map {
case (field, value) => s""""${field}":${value}"""
}
.mkString("{", ",", "}")
}
def shapelessAny(): Unit = {
def toJSONString(elem: Any): String = elem match {
case elem: Int => s"${elem}"
case elem: String => s""""${elem}""""
}
val userGen = LabelledGeneric[User]
val fields: List[String] =
Keys[userGen.Repr].apply.toList[Symbol].map(_.name)
val values = user.productIterator.toList.map(toJSONString)
val json = fields
.zip(values)
.map {
case (field, value) => s""""${field}":${value}"""
}
.mkString("{", ",", "}")
}
def circe(): Unit = {
val json = user.asJson.noSpaces
}
val mapper = new ObjectMapper
mapper.registerModule(DefaultScalaModule)
def jackson(): Unit = {
val json = mapper.writeValueAsString(user)
}
def noBottleneck(): Unit = {
val json = s"""{"name":"${user.name}","age":${user.age}"""
}
}
@uzimith
Copy link
Author

uzimith commented Dec 10, 2018

[info] Benchmark                 Mode  Cnt         Score       Error  Units
[info] Bench.benchCirce         thrpt   40   1851757.798 ±  5557.314  ops/s
[info] Bench.benchJackson       thrpt   40   6179486.273 ± 24369.406  ops/s
[info] Bench.benchNoBottleneck  thrpt   40  18240872.473 ± 63760.564  ops/s
[info] Bench.benchReflection    thrpt   40   1742759.537 ±  6340.425  ops/s
[info] Bench.benchShapeless     thrpt   40   2192613.754 ± 18533.675  ops/s
[info] Bench.benchShapelessAny  thrpt   40   2558311.950 ± 14235.556  ops/s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment