2

アルゴナウトを使用して、オブジェクトのリストをjsonに変換しようとしています。リストには、さまざまなタイプの検証エラーのリストが含まれています。たとえば、' MissingParameter ' または ' InvalidParameter ' またはその他のタイプのインスタンスを含めることができます。上記の両方のクラスに EncodeJson (argonaut) コーデックを定義しました。上記のタイプのリストをアルゴナウトを使用して json に変換する方法はありますか? つまり、次のことを達成できますか?

List(new MissingParameter("name"), new InvalidParameter("email")).asJson
4

2 に答える 2

2

Feyyaz による解決策は、可能な限り最良の解決策のようです。考えられるすべてのサブクラスのパターン マッチングを回避するために、親でコントラクトを定義しているため、すべてのサブクラスがエンコーダーを提供する必要があります。完璧かどうかはわかりませんが、期待どおりの動作をします。同様の解決策を探している人に役立つことを願っています。

import argonaut._, Argonaut._
import scala.collection.TraversableLike

trait HasEncoder[T <: HasEncoder[T]] { self: T =>
  def encoder: EncodeJson[T]
  lazy val json = encoder.encode(self)
}

object HasEncoder {
  implicit def listToRichHasEncoderList[A <: HasEncoder[_], Repr](coll: TraversableLike[A, Repr]): RichHasEncoderList[A, Repr] = new RichHasEncoderList[A, Repr](coll)
}

class RichHasEncoderList[A <: HasEncoder[_], Repr](coll: TraversableLike[A, Repr]) {
  lazy val json = jArray(coll.toList.map(_.json))
} 

上記のソリューションでは、アルゴナウトはリストが json 配列 (jArray) を構築することを期待しているため、トラバース可能なものはすべて受け入れてリストに変換する必要がありました。その部分を改善できるかどうかはわかりません。

そしてテストケース(暗黙の「json」値がリストで利用できるように、上記のコードが存在するパッケージを必ずインポートしてください):

import argonaut._, Argonaut._
import org.scalatest.{Matchers, FlatSpec}

/**
  * Created by jamesanto on 12/17/15.
  */
class HasEncoderTest extends FlatSpec with Matchers {

  case class MissingParameter(name: String) extends HasEncoder[MissingParameter] {
    override def encoder: EncodeJson[MissingParameter] = casecodec1(MissingParameter.apply, MissingParameter.unapply)("name")
  }

  case class InvalidParameter(name: String, expected: String, actual: String) extends HasEncoder[InvalidParameter] {
    override def encoder: EncodeJson[InvalidParameter] = casecodec3(InvalidParameter.apply, InvalidParameter.unapply)("name", "expected", "actual")
  }

  it should "encode list of objects of classes that extend HasEncoder" in {
    val list = List(MissingParameter("email"), InvalidParameter("dob", "DOB in yyyy/MM/dd format", "10/10/1985"))
    list.json.nospaces should be ("""[{"name":"email"},{"name":"dob","expected":"DOB in yyyy/MM/dd format","actual":"10/10/1985"}]""")
  }
}
于 2015-12-17T08:11:41.000 に答える
1

私はアルゴナウトを使用していませんが、ここでの問題は一般的な問題だと思います。ここでのリストのタイプは ですList[Product with Serializable]。また、コンパイラはそれを Json にシリアル化する方法を知りません。

Parameter トレイトを作成し、それを使用してクラスを拡張し、すべての型をパターン マッチングでチェックする Parameter のシリアライザーを作成することをお勧めします。

注: 私は play-json ライブラリを使用しています。それをアルゴナウトに適合させる必要があります。

import play.api.libs.json.{Writes, JsValue, Json}
import play.api.libs.json.Writes._

trait Parameter

case class MissingParameter (paramName: String) extends Parameter

case class InvalidParameter (paramName: String) extends Parameter

implicit val writes1 = Json.writes[MissingParameter]
implicit val writes2 = Json.writes[InvalidParameter]

implicit val implicitParamWrites = new Writes[Parameter] {
  def writes(param: Parameter): JsValue = {
    param match {
      case missing: MissingParameter => Json.toJson(missing)
      case invalid: InvalidParameter => Json.toJson(invalid)
    }
  }
}

val list: List[Parameter] = List( MissingParameter("p1"), InvalidParameter("i1") )

Json.toJson(list)
于 2015-12-15T15:38:36.440 に答える