When materializing a GenCodec
for sealed hierarchy with @flatten
annotation, you can use this
annotation on one of case classes or objects to mark it as the default one.
Changes the serialization format used by GenCodec
s automatically derived for sealed hierarchies.
Changes the serialization format used by GenCodec
s automatically derived for sealed hierarchies.
The format is changed from "nested" to "flat".
@flatten sealed trait Value case class Numeric(int: Int) extends Value case class Textual(string: String) extends Value object Value { implicit val codec: GenCodec[Value] = GenCodec.materialize[Value] }
Without flatten annotation, the "nested" format is used, e.g. when Numeric(42)
would be encoded to JSON
as:
{"Numeric": {"int": 42}}
but when flatten annotation is applied on sealed trait/class, then it changes to:
{"_case": "Numeric", "int": 42}
The "_case" field name can be customized with annotation parameter
May be used on members of objects, case classes or any types having companion object with case class
like apply
and unapply
/unapplySeq
methods in order to add additional, generated fields to data serialized by
auto-materialized GenCodec
s.
May be used on members of objects, case classes or any types having companion object with case class
like apply
and unapply
/unapplySeq
methods in order to add additional, generated fields to data serialized by
auto-materialized GenCodec
s.
case class User(id: Long, login: String) { @generated def upperLogin: String = login.toUpperCase } object User { implicit val codec: GenCodec[User] = GenCodec.materialize[User] }
This annotation may be applied on val
s, var
s and def
s. When applied on a def
, it must be either parameterless
(no parameter lists or empty parameter list) or accept only implicit parameters, provided that all the implicit values
are available in the scope where GenCodec
is materialized (implicit values will be "baked in" the codec).
NOTE: @generated
annotation may be defined on any level of inheritance hierarchy - it will be inherited
from implemented and overridden members.
Can be used on case class fields and classes in sealed hierarchy to instruct automatically derived GenCodec
to use particular name instead of just using parameter or class name.
Can be used on case class fields and classes in sealed hierarchy to instruct automatically derived GenCodec
to use particular name instead of just using parameter or class name.
For example:
sealed trait Base @name("STH") case class Something(@name("dbname") paramname: Int) extends Base object Base { implicit codec = GenCodec.auto[Base] }
GenCodec.write[Base](someOutput, Something(42))
would write an object
{"STH": {"dbname": 42}}
instead of {"Something": {"paramname": 42}}
.
NOTE: @name
annotation may be defined on any level of inheritance hierarchy.
For instance, if a case class field overrides a method of some base trait, the @name
annotation may
be used on that method and will affect the case class field.
To be used in conjunction with flatten.
To be used in conjunction with flatten.
It can be applied on one or more of case class fields in a sealed hierarchy to instruct the
auto-materialized GenCodec
that this particular field may appear before _case
field in the serialized format
during reading.
@flatten sealed trait Base case class FirstCase(@outOfOrder tag: String, int: Int) extends Base case class SecondCase(dbl: Double) extends Base object Base { implicit val codec: GenCodec[Base] = GenCodec.materialize[Base] }
The following JSON (assuming this is the representation used) would correctly deserialize as
FirstCase("someTag", 42)
:
{"tag": "someTag", "_case": "FirstCase", "int": 42}
Field annotated with @outOfOrder
annotation doesn't have to be present in every case class, but if it is present,
all case classes must annotate it and give it exactly the same type. The annotation may also be inherited, e.g.
@flatten sealed trait Base { @outOfOrder def tag: String } case class FirstCase(tag: String, int: Int) extends Base case class SecondCase(tag: String, dbl: Double) extends Base
The direct motivation for this annotation was the ability to use flatten on MongoDB entities with an _id
field.
When reading entities from MongoDB, the _id
field is always at the beginning of a BSON document and therefore
GenCodec
must be able to read it before it knows which case class of sealed hierarchy is being deserialized.
If some case class field has default value or whenAbsent annotation, you can use transientDefault
on this field to instruct an automatically derived GenCodec
to not persist the value of that field if
it's equal to the default value.
If some case class field has default value or whenAbsent annotation, you can use transientDefault
on this field to instruct an automatically derived GenCodec
to not persist the value of that field if
it's equal to the default value.
For example:
case class Something(str: String, @transientDefault int: Int = 42) object Something { implicit val codec = GenCodec.auto[Something] }
GenCodec.write(someOutput, Something("lol", 10))
would yield object {"str": "lol", "int": 10}
but
GenCodec.write(someOutput, Something("lol", 42))
would yield object {"str": "lol"}
because the value of int
is the same as the default value.
NOTE: transientDefault also works for method parameters in RPC framework.
Can be used on case classes with exactly one field to instruct automatically generated GenCodec
that the
class is a "transparent wrapper" and should be serialized to the same representation as the value of its sole
field.
An alternative way to provide default value for case class parameter used during deserialization with GenCodec
when its field is missing in data being deserialized.
An alternative way to provide default value for case class parameter used during deserialization with GenCodec
when its field is missing in data being deserialized. Normally, Scala-level default parameter values are picked
up, but you may want to use this annotation instead if you don't want to pollute your Scala classes with
unintended default parameter values (i.e. you want a default value *only* for deserialization).
case class HasDefault(@whenAbsent("default") str: String) object HasDefault extends HasGenCodec[HasDefault]
If a parameter has both Scala-level default value and is annotated with @whenAbsent
then value from annotation
takes priority. You can use this to have different source-level default value and different
default value for deserialization. You can also leverage this to "remove" default value for deserialization:
case class HasNoDefault(@whenAbsent(throw new Exception) str: String = "default") object HasDefault extends HasGenCodec[HasDefault]
NOTE: whenAbsent also works for method parameters in RPC framework.
When materializing a
GenCodec
for sealed hierarchy with@flatten
annotation, you can use this annotation on one of case classes or objects to mark it as the default one. If during deserialization the codec is unable to find the_case
field and determine the case class/object to deserialize, it will try to deserialize the data to the class/object marked with this annotation.This is useful for retaining backwards compatibility with serialized format when refactoring code and replacing a simple case class with a sealed hierarchy.