Посмотрим, что происходит при генерации энкодера. Circe использует бесформенный для получения своих кодеков, так что достаточно проверить, что решает бесформенный, чтобы ответить на ваш вопрос. Так что в аммоните:
@ 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
. Справедливо: бесформенный способ - извлечь все поля, доступные в конструкторе, преобразуя его одним способом, и вернуть все поля обратно через конструктор, если преобразуется другим.
По сути, все деривации классов типов работают таким образом, поэтому вы должны сделать возможным передать _id
в качестве конструктора:
abstract class RecordObject {
val _id: String
}
case class PersonRecord(
name: String,
_id: String = BSONObjectID.generate().stringify
) extends RecordObject
Это поможет производным классам типов выполнить свою работу. Если вы не можете изменить то, как выглядит PersonRecord
... тогда да, вы должны написать свой собственный код c. Хотя я сомневаюсь, что это будет легко, поскольку вы сделали _id
неизменным и невозможно установить извне с помощью конструктора, так что это также будет трудно реализовать любым другим способом.