µPickle 在编译时工作(宏在编译时工作)。为了为具有子类实例的特征派生类型类实例,您应该在编译时了解所有特征子类。这仅适用于密封特征(通过knownDirectSubclasses
https://github.com/lihaoyi/upickle/blob/master/implicits/src/upickle/implicits/internal/Macros.scala#L124)。
http://www.lihaoyi.com/upickle/#SupportedTypes
支持的类型
开箱即用,uPickle 支持写入和读取以下类型:
- 布尔值、字节、字符、短整型、整型、长整型、浮点型、双精度
- 从 1 到 22 的元组
- 不可变的 Seq、List、Vector、Set、SortedSet、Option、Array、Maps 和所有其他具有合理 CanBuildFrom 实现的集合
- 持续时间,无论是
- 独立案例类和案例对象,以及它们的通用等价物,
- 作为密封特征或密封类层次结构一部分的非泛型案例类和案例对象
- 密封特征和密封类本身,假设所有子类都是可腌制的
- UUID
- 无效的
如您所见,仅支持密封特征。
解决方法是在多个源文件中使用密封特征和自定义pickler 的公共父特征。
trait Base
object Base {
implicit val rw: ReadWriter[Base] = readwriter[ujson.Value].bimap[Base]({
case c: Base1 => writeJs(c)
case c: Base2 => writeJs(c)
},
s => Try(read[Base1](s)).getOrElse(read[Base2](s))
)
}
sealed trait Base1 extends Base
object Base1 {
implicit val rw: ReadWriter[Base1] = ReadWriter.merge(C1.rw, C11.rw)
}
case class C1(x: Int) extends Base1
object C1 {
implicit val rw: ReadWriter[C1] = macroRW
}
case class C11(x: Int) extends Base1
object C11 {
implicit val rw: ReadWriter[C11] = macroRW
}
sealed trait Base2 extends Base
object Base2 {
implicit val rw: ReadWriter[Base2] = ReadWriter.merge(C2.rw, C22.rw)
}
case class C2(s: String) extends Base2
object C2 {
implicit val rw: ReadWriter[C2] = macroRW
}
case class C22(s: String) extends Base2
object C22 {
implicit val rw: ReadWriter[C22] = macroRW
}
val c1: Base = new C1(0)
val c2: Base = new C2("X")
val c1String = write(c1)
val c2String = write(c2)
println("c1 " + c1String) // c1 {"$type":"App.C1","x":0}
println("c2 " + c2String) // c2 {"$type":"App.C2","s":"X"}
println(read[Base](c1String)) // C1(0)
println(read[Base](c2String)) // C2(X)