ここで私はcirceで一般的に特異一部を行うと考えることができます最も簡単な方法についてです:あなたはこのようなGenericResource
を拡張し、いくつかのケースクラスを持っているならば、
import io.circe.{ Decoder, Encoder, Json }
import io.circe.generic.encoding.DerivedObjectEncoder
trait GenericResource {
val singularName: String
val pluralName: String
}
object GenericResource {
implicit def encodeResource[A <: GenericResource](implicit
derived: DerivedObjectEncoder[A]
): Encoder[A] = Encoder.instance { a =>
Json.obj(a.singularName -> derived(a))
}
}
そして:
case class Product(name: String) extends GenericResource {
val singularName = "product"
val pluralName = "products"
}
あなたは(ケースクラスのすべてのメンバーがエンコード可能であると仮定して)これを行うことができます:
などはありません定型、余分な輸入、
キルケが自動的Encoder
を持つ任意のA
ためSeq[A]
エンコーダを提供するので、Seq
場合は、少し複雑ですが、それはあなたが欲しい、それが何をしていないだけでアイテムをエンコードし、JSON配列に貼り付けます。あなたはこのような何か書くことができます。
implicit def encodeResources[A <: GenericResource](implicit
derived: DerivedObjectEncoder[A]
): Encoder[Seq[A]] = Encoder.instance {
case values @ (head +: _) =>
Json.obj(head.pluralName -> Encoder.encodeList(derived)(values.toList))
case Nil => Json.obj()
}
をそして、このようにそれを使用します。
scala> Seq(Product("car"), Product("truck")).asJson.noSpaces
res1: String = {"products":[{"name":"car"},{"name":"truck"}]}
しかし、あなただけのコンパニオンオブジェクトでそれを固執し、すべてが動作し、あなたがして、それを配置する必要が期待することはできません必要なときにインポートします(そうでない場合は、デフォルトのSeq[A]
インスタンスと同じ優先度が設定されます)。
このencodeResources
実装の別の問題は、Seq
が空の場合、それはちょうど空のオブジェクトを返すことです。
scala> Seq.empty[Product].asJson.noSpaces
res2: String = {}
複数の名前は、インスタンス・レベルでリソースに接続されているので、これは、あなたの場合インスタンスを持っていないので、それを取得する方法はありません(リフレクションの不足)。もちろん、nullをコンストラクタなどに渡すことで、偽のインスタンスを作成することはできますが、それはこの質問の範囲外です。
エンコードしたこのJSONをデコードする必要がある場合は、この問題(インスタンスにアタッチされるリソース名)も問題になります。そのような場合は、特定のリソースタイプのコンパニオンオブジェクトに混在させ、そこに名前を示すような形のものがある場合は、少し異なるアプローチを検討することをお勧めします。GenericResourceCompanion
それがオプションでない場合は、おそらく反射や偽のインスタンス、またはその両方に悩まされているでしょう(しかし、おそらくこの質問の対象外です)。
ワウ、詳細なソリューションに感謝します。 –