这是以下问题的后续:在Scala中获取case类字段名的最快方法
我正试图找到一种简单的方法来提供快速自定义序列化(让我们说到(String, Object)
的元组列表,它可以在生产中转换为db行或在单元测试中转换为内存映射)到Scala中的case类家族,似乎保持类字段的缓存列表可能是一种很有前途的方法。然而,我不确定最干净的方法是什么。我知道我可以做如下的事情:
case class Playlist(
val id: Option[Long],
val title: Option[String],
val album: Option[String],
val artist: Option[String],
val songId: Option[UUID]) {
def serialize = Playlist.fields.map(f => (f.getName, f.get(this)))
}
object Playlist {
val empty = Playlist(None, None, None, None, None)
val fields = Playlist.empty.getClass.getDeclaredFields.toList
fields foreach { _.setAccessible(true) }
}
然而,我不喜欢这一点:
- 我不想从同伴类中使用
empty
只是为了获得缓存的字段列表 - 我不想为每个我想要序列化行为的case类声明序列化逻辑。可能有一些方法可以绕过这个问题,但我不确定最干净的方法会给出正确的行为(担心混合反射和继承)
在Scala中实现这个最干净的方法是什么?
我认为将Class[_] -> fields
的缓存映射与任何个案类分开是最简单的,例如在具有serialize(instance)
方法的全局单例中。这样,您就不必在希望序列化的类中编写任何额外的代码。
另一种方法可能是创建一个trait来混合case类的同伴对象,缓存字段列表,以及一个隐式包装类来添加serialize
方法。您可以使用隐式ClassTag
来初始化fields
:
abstract class MyCompanion[T](implicit ctag: ClassTag[T]) {
private val fields = ctag.runtimeClass.getDeclaredFields.toList
fields foreach { _.setAccessible(true) }
implicit class AddSerializeMethod(obj: T) {
def serialize = fields.map(f => (f.getName, f.get(obj)))
}
}
case class C(...) { ... }
object C extends MyCompanion[C]
不幸的是,你似乎不能使AddSerializeMethod
一个值类的这种方式。