Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Circe asJson未编码抽象基类中的属性_Json_Scala_Circe_Http4s Circe - Fatal编程技术网

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社区似乎比一年前更加活跃