Circe asJson не кодирует свойства из абстрактного базового класса
Предположим, у меня есть следующий абстрактный базовый класс:
package Models
import reactivemongo.bson.BSONObjectID
abstract class RecordObject {
val _id: String = BSONObjectID.generate().stringify
}
Который расширен следующим конкретным классом case:
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"?
Как видите, недвижимость _id: String
унаследовано от RecordObject
пропал, отсутствует. Я ожидал, что встроенный кодировщик должен нормально работать в этом случае. Мне действительно нужно создавать свою собственную?
1 ответ
Посмотрим, что происходит при генерации кодировщика. 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
ОК, так что это String :: HNil
. Достаточно справедливо - то, что делает shapeless, - это извлечение всех полей, доступных в конструкторе, с преобразованием в одну сторону и возвращение всех полей через конструктор при преобразовании в другую.
По сути, все производные от классов типов работают таким образом, поэтому вы должны сделать возможным передачу _id
как конструктор:
abstract class RecordObject {
val _id: String
}
case class PersonRecord(
name: String,
_id: String = BSONObjectID.generate().stringify
) extends RecordObject
Это помогло бы наследованию классов типов выполнять свою работу. Если вы не можете изменить, какPersonRecord
похоже... тогда да надо написать свой кодек. Хотя я сомневаюсь, что это будет легко, как ты_id
неизменяемый и невозможно установить извне через конструктор, поэтому его также сложно реализовать каким-либо другим способом.