mpollmeier / scalameta-serialiser   0.0.7

Apache License 2.0 GitHub

Serialise and deserialise classes using scala.meta

Scala versions: 2.12 2.11

Build Status Scaladex

Setup with sbt

Get the latest version of scalameta-serialiser and the scalameta compiler plugin

libraryDependencies += "com.michaelpollmeier" %% "scalameta-serialiser" % "LATEST_VERSION"
addCompilerPlugin("org.scalameta" % "paradise" % "3.0.0-M10" cross CrossVersion.full)

Usage

Just annotate your case class with @mappable to wire in this macro. It will create a serialiser and deserialiser for the annotated class.

import scala.meta.serialiser._

@mappable case class SimpleCaseClass(i: Int, s: String)

val testInstance = SimpleCaseClass(i = 42, s = "something")
val keyValues: Map[String, Any] = testInstance.toMap
SimpleCaseClass.fromMap(keyValues) // result: Success(testInstance)

Features

  • map class members to different names: @mappedTo("iMapped") i: Int
  • mark class members as nullable: @nullable nullableValue: String
  • Option types
  • default values
  • keeps existing body of the annotated class
  • keeps existing companion object, injects the generated typeclasses
  • inject your own config for later use, useful when using this in a library: @mappable(Map("param1" -> "value1")) -> you can lookup the entries of that Map at runtime in the companion and the generated typeclass instances.

All of the above are covered in MappableTest.scala.

Understand what's going on

Annotating any case class with mappable will generate typeclass instances FromMap and ToMap that let you serialise and deserialise that specific case class. These typeclass instances end up in the companion object.

trait ToMap[A] {
  def apply(a: A): Map[String, Any]
  def annotationParams: Map[String, Any] = Map.empty
}

trait FromMap[A] {
  def apply(keyValues: Map[String, Any]): Try[A]
  def annotationParams: Map[String, Any] = Map.empty
}

If you want to see the generated code, simply turn on debug mode:

@mappable(Map("_debug" -> "true"))
case class WithDebugEnabled(i: Int)

TODOs

  • smart matching for property name if there's no direct match
    • different casing
    • camelCase
    • snake_case_
    • only take the smart match if there's one option. if it's ambiguous: fail
  • get maps of specific types
  • support for multiple constructor parameter lists
  • allow to switch between null entry and missing entry in Map when dealing with an Option type (currently maps to null)

sbt command to compile and test this project

;clean;examples/clean;examples/test

release a new version from sbt

  • release #will do a cross release
  • sonatypeReleaseAll

Talk at ScalaDays 2017 Chicago code generation with scala.meta

Video and slides