Circe asJson未编码抽象基类中的属性
假设我有以下抽象基类:Circe asJson未编码抽象基类中的属性,json,scala,circe,http4s-circe,Json,Scala,Circe,Http4s Circe,假设我有以下抽象基类: package Models import reactivemongo.bson.BSONObjectID abstract class RecordObject { val _id: String = BSONObjectID.generate().stringify } package Models case class PersonRecord(name: String) extends RecordObject 通过以下具体案例类别进行扩展: pa
package Models
import reactivemongo.bson.BSONObjectID
abstract class RecordObject {
val _id: String = BSONObjectID.generate().stringify
}
package Models
case class PersonRecord(name: String) extends RecordObject
通过以下具体案例类别进行扩展:
package Models
import reactivemongo.bson.BSONObjectID
abstract class RecordObject {
val _id: String = BSONObjectID.generate().stringify
}
package Models
case class PersonRecord(name: String) extends RecordObject
然后,我尝试使用以下代码获取JSON字符串:
import io.circe.syntax._
import io.circe.generic.auto._
import org.http4s.circe._
// ...
val person = new PersonRecord(name = "Bob")
println(person._id, person.name) // prints some UUID and "Bob"
println(person.asJso) // {"name": "Bob"} -- what happened to "_id"?
如您所见,从
RecordObject
继承的属性\u id:String
丢失。我希望内置编码器在这个用例中可以正常工作。我真的需要构建自己的吗?让我们看看编码器生成过程中会发生什么。Circe使用shapeless来派生其编解码器,因此只要检查shapeless解析为什么就足以回答您的问题。所以在菊石中:
@ abstract class RecordObject {
val _id: String = java.util.UUID.randomUUID.toString
}
defined class RecordObject
@ case class PersonRecord(name: String) extends RecordObject
defined class PersonRecord
@ import $ivy.`com.chuusai::shapeless:2.3.3`, shapeless._
import $ivy.$ , shapeless._
@ Generic[PersonRecord]
res3: Generic[PersonRecord]{type Repr = String :: shapeless.HNil} = ammonite.$sess.cmd3$anon$macro$2$1@1123d461
好的,它的字符串::HNil
。足够公平-Shapess所做的是提取构造函数中的所有可用字段,并以一种方式转换,如果以另一种方式转换,则将所有字段放回构造函数
基本上所有类型类派生都是这样工作的,因此您应该能够将\u id
作为构造函数传递:
abstract class RecordObject {
val _id: String
}
case class PersonRecord(
name: String,
_id: String = BSONObjectID.generate().stringify
) extends RecordObject
这将有助于类型类派生完成其工作。如果您无法更改
PersonRecord
的外观。。。然后是的,你必须写你自己的编解码器。尽管我怀疑这会很容易,因为您使\u id
不可变,并且不可能通过构造函数从外部进行设置,因此使用任何其他方法也很难实现。让我们看看编码器生成过程中会发生什么。Circe使用shapeless来派生其编解码器,因此只要检查shapeless解析为什么就足以回答您的问题。所以在菊石中:
@ abstract class RecordObject {
val _id: String = java.util.UUID.randomUUID.toString
}
defined class RecordObject
@ case class PersonRecord(name: String) extends RecordObject
defined class PersonRecord
@ import $ivy.`com.chuusai::shapeless:2.3.3`, shapeless._
import $ivy.$ , shapeless._
@ Generic[PersonRecord]
res3: Generic[PersonRecord]{type Repr = String :: shapeless.HNil} = ammonite.$sess.cmd3$anon$macro$2$1@1123d461
好的,它的字符串::HNil
。足够公平-Shapess所做的是提取构造函数中的所有可用字段,并以一种方式转换,如果以另一种方式转换,则将所有字段放回构造函数
基本上所有类型类派生都是这样工作的,因此您应该能够将\u id
作为构造函数传递:
abstract class RecordObject {
val _id: String
}
case class PersonRecord(
name: String,
_id: String = BSONObjectID.generate().stringify
) extends RecordObject
这将有助于类型类派生完成其工作。如果您无法更改
PersonRecord
的外观。。。然后是的,你必须写你自己的编解码器。虽然我怀疑这会很容易,因为您使\u id
不可变,并且不可能通过构造函数从外部进行设置,因此使用任何其他方法也很难实现。谢谢您的精彩回答!我有一种感觉,这与我对Scala中的继承理解不足有关。这确实有效,但现在由继承自RecordObject
的类负责实现ID生成。我希望这是自动的,并且一旦类被实例化,ID就不可更改。有什么方法可以做到这一点吗?您必须定义一个构造函数,允许您重写\u id
-否则如何使用特定id重新创建实例?但是,您可以在RecordObject
中创建一个protected
方法generateID
,并重载构造函数以使用它:def this(name:String)=this(name,generateID)
。不过,您永远无法确定扩展界面的用户是否会使用它。由于您仍然需要从外部世界传递任意的字符串
,因此对其进行约束是没有意义的。这个字符串可能在到达构造函数之前的任何时候被破坏。我要做的只是创建一个单独的类型来表示BSONObjectID
。这种类型将有两个公共方法来创建自己,一个将String
解析为类似的东西[Error,BSONObjectID]
,另一个用于创建新ID的方法。然后,我将手动编写该ID的编解码器,以确保如果ID被破坏,它将无法循环解析。在这一点上,我不必担心下游可能会以错误的方式使用ID,因为他们不可能这样做。明白了。非常感谢您的帮助、时间和快速回复。我感到惊喜的是,SO上的Scala社区似乎比一年前更加活跃。我想查找诸如:类型类派生、使非法状态不可替代、ADT以及类型和隐式之类的内容不会有什么坏处。谢谢您的精彩回答!我有一种感觉,这与我对Scala中的继承理解不足有关。这确实有效,但现在由继承自RecordObject
的类负责实现ID生成。我希望这是自动的,并且一旦类被实例化,ID就不可更改。有什么方法可以做到这一点吗?您必须定义一个构造函数,允许您重写\u id
-否则如何使用特定id重新创建实例?但是,您可以在RecordObject
中创建一个protected
方法generateID
,并重载构造函数以使用它:def this(name:String)=this(name,generateID)
。不过,您永远无法确定扩展界面的用户是否会使用它。由于您仍然需要从外部世界传递任意的字符串
,因此对其进行约束是没有意义的。这个字符串可能在到达构造函数之前的任何时候被破坏。我要做的只是创建一个单独的类型来表示BSONObjectID
。这种类型将有两个公共方法来创建自己,一个将String
解析为类似的东西[Error,BSONObjectID]
,另一个用于创建新ID的方法。然后,我将手动编写该ID的编解码器,以确保如果ID被破坏,它将无法循环解析。在这一点上,我不必担心下游可能会以错误的方式使用ID,因为他们不可能这样做。明白了。非常感谢您的帮助、时间和快速回复。我惊喜地发现,SO上的Scala社区似乎比一年前更加活跃