2017-08-25 2 views
1

Ich versuche, ein Spiel Json liest aus beliebigen Fall Klasse mit formlosen zu tun.benutzerdefinierte Art Klasse mit glatter pb mit impliziter Auflösung

Im Moment folgendes zu implementieren Ich bin versucht, die Schritte

Von T, ich habe ein Fieldtype [K1, V1] :: Fieldtype [K2, V2] :: ... mit LabelledGeneric

Dann möchte ich einen hList des Typs bauen Liest [V1] :: [V2] Liest ...

Hier ist der Code ich bin mit:

/* 
    * To build the json reads from T 
    */ 
    trait HReads[PRepr <: HList] { 
    type Out 
    def reads: Out 
    } 

    object HReads { 
    type Aux[PRepr <: HList, Out1 <: HList] = HReads[PRepr] { type Out = Out1 } 

    implicit def readsHNil(): Aux[HNil, HNil] = new HReads[HNil] { 
     type Out = HNil 
     override def reads: Out = { 
     throw new RuntimeException("Oups") 
     } 
    } 

    implicit def readsSingleton[T, K <: Symbol](
     implicit 
     kWitness: Witness.Aux[K], 
     jsReads: play.api.libs.json.Reads[T] 
    ): Aux[FieldType[K, T] :: HNil, Reads[T] :: HNil] = new HReads[FieldType[K, T] :: HNil] { 
     type Out = Reads[T] :: HNil 
     override def reads: Out = { 
     val name: String = kWitness.value.name 
     val pathReads: Reads[T] = (__ \ name).read[T](jsReads) 
     pathReads :: HNil 
     } 
    } 

    implicit def readsStd[T, K <: Symbol, RestRepr <: HList, Rest <: HList](
    implicit 
    kWitness: Witness.Aux[K], 
    jsReads: Reads[T], 
    hreads: Lazy[HReads.Aux[RestRepr, Rest]] 
    ): Aux[FieldType[K, T] :: RestRepr, Reads[T] :: Rest] = new HReads[FieldType[K, T] :: RestRepr] { 
     type Out = Reads[T] :: Rest 
     override def reads: Out = { 
     val name: String = kWitness.value.name 
     val pathReads: Reads[T] = (__ \ name).read[T](jsReads) 
     val value: Rest = hreads.value.reads 
     pathReads :: value 
     } 
    } 

    def jsonReads[P]: JsonReads[P] = new JsonReads[P] {} 

    implicit class JsonReadsOps[In](in: JsonReads[In]) { 
     def jsonReads[K <: Symbol, T, InRepr <: HList, HR <: HList]()(
      implicit 
      gen: LabelledGeneric.Aux[In, FieldType[K, T] :: InRepr], 
      hreads: HReads.Aux[FieldType[K, T] :: InRepr, Reads[T] :: HR] 
    ): Reads[T] :: HR = { 
     hreads.reads 
     } 
    } 
    } 

    // And trying to use this like that : 
    import HReads._ 

    implicit val l = LabelledGeneric[MonPojo] 

    private val allReads = jsonReads[MonPojo].jsonReads() 
    println(s"All Reads $allReads") 
    //[error] validation\validation.scala:428: could not find implicit value for parameter hreads: validation.validations.HReads.Aux[shapeless.labelled.FieldType[K,T] :: InRepr,play.api.libs.json.Reads[T] :: HR] 
    //[error] private val allReads = jsonReads[MonPojo].jsonReads() 
    //[error]             ^
    //[error] one error found 

ist jemand könnte mir helfen?

Danke Alex.

Antwort

0

ist hier die Umsetzung von ReadsWithRules:

trait ReadsWithRules[T, R <: HList] { 
    def withRules(rules: R): Reads[T] 
    } 

    trait ReadsWithRulesLowerPriority { 
    implicit def readsNoRule[T](implicit reads: Reads[T]): ReadsWithRules[T, HNil] = new ReadsWithRules[T, HNil] { 
     override def withRules(rules: HNil): Reads[T] = reads 
    } 

    implicit def readsGeneric[Repr, A, R <: HList](implicit 
                gen: LabelledGeneric.Aux[A, Repr], 
                readsRepr: Lazy[ReadsWithRules[Repr, R]] 
               ): ReadsWithRules[A, R] = 
     new ReadsWithRules[A, R] { 
     override def withRules(rules: R): Reads[A] = { 
      readsRepr.value.withRules(rules).map(r => gen.from(r)) 
     } 
     } 

    } 

    object ReadsWithRules extends ReadsWithRulesLowerPriority { 
    implicit def readHNil[R <: HList]: ReadsWithRules[HNil, R] = new ReadsWithRules[HNil, R] { 
     override def withRules(rules: R): Reads[HNil] = implicitly[Reads[HNil]] 
    } 

    implicit def readNoRuleForHead[K <: Symbol, H, T <: HList, R <: HList](implicit 
                      witness: Witness.Aux[K], 
                      noRule: LacksKey[R, K], 
                      readsH: Reads[H], 
                      readsT: ReadsWithRules[T, R] 
                     ): ReadsWithRules[FieldType[K, H] :: T, R] = 
     new ReadsWithRules[FieldType[K, H] :: T, R] { 
     override def withRules(rules: R): Reads[FieldType[K, H] :: T] = new Reads[FieldType[K, H] :: T] { 
      override def reads(json: JsValue): JsResult[FieldType[K, H] :: T] = { 
      val name = witness.value 
      val rH = (__ \ name).read(readsH) 
      (rH and readsT.withRules(rules)) ((a, b) => (name ->> a :: b).asInstanceOf[FieldType[K, H] :: T]).reads(json) 
      } 
     } 
     } 

    implicit def readRuleForHead[K <: Symbol, H, T <: HList, R <: HList](implicit 
                     witness: Witness.Aux[K], 
                     at: shapeless.ops.record.Selector.Aux[R, K, Reads[H]], 
                     readsH: Reads[H], 
                     readsT: ReadsWithRules[T, R] 
                     ): ReadsWithRules[FieldType[K, H] :: T, R] = 
     new ReadsWithRules[FieldType[K, H] :: T, R] { 
     override def withRules(rules: R): Reads[FieldType[K, H] :: T] = new Reads[FieldType[K, H] :: T] { 
      override def reads(json: JsValue): JsResult[FieldType[K, H] :: T] = { 
      val name = witness.value 
      val additionalRule: Reads[H] = at(rules) 
      val rH = (__ \ name).read(readsH) andKeep (__ \ name).read(additionalRule) 
      (rH and readsT.withRules(rules)) ((a, b) => (name ->> a :: b).asInstanceOf[FieldType[K, H] :: T]).reads(json) 
      } 
     } 
     } 

    } 

    def readsWithRules[T, R <: HList](rules: R)(implicit readWithRule: ReadsWithRules[T, R]): Reads[T] = 
    readWithRule.withRules(rules) 

    case class MonPojo(numericField: Int) 

    val r: Reads[MonPojo] = 
     readsWithRules[MonPojo, FieldType[Symbol with Tagged["numericField"], Reads[Int]] :: HNil](
     ('numericField ->> (min(0) keepAnd max(150))) :: HNil 
    ) 
    println(
    r.reads(Json.obj(
     "stringField" -> "Tata", 
     "numericField" -> 42 
    )) 
) 

    //JsSuccess(MonPojo(42),) 
0

Dann möchte ich einen hList des Typs bauen Liest [V1] :: Liest [V2] ...

Es ist nicht klar, warum Sie eine hList von benötigen Liest anstatt von hList Liest (also ich denke du brauchst keine andere typklasse HReads, Read sollte genug sein). Ich denke, Sie müssen implicits implementieren:

implicit val readsHNil: Reads[HNil] = ??? 

implicit def readHCons[K <: Symbol, H, T <: HList](implicit 
                witness: Witness.Aux[K], 
                readsH: Reads[H], 
                readsT: Reads[T]): Reads[FieldType[K, H] :: T] = ??? 

implicit def readsGeneric[Repr, A](implicit 
            gen: LabelledGeneric.Aux[A, Repr], 
            readsRepr: Lazy[Reads[Repr]]): Reads[A] = ??? 

und zwei ähnliche für Coproducts, wenn Sie brauchen.

Ich schrieb einige Implementierungen

import shapeless.{:+:, ::, CNil, Coproduct, HList, HNil, Inl, LabelledGeneric, Lazy, Witness} 
    import shapeless.labelled.FieldType 
    import play.api.libs.json._ 
    import shapeless.syntax.singleton._ 

    implicit val readsHNil: Reads[HNil] = Reads { 
    case JsArray(values) if values.isEmpty => JsSuccess(HNil) 
    case JsObject(values) if values.isEmpty => JsSuccess(HNil) 
    case _ => JsError() 
    } 

    private def listToJsResult[K <: Symbol, H, T <: HList](l: List[JsValue])(implicit 
                      witness: Witness.Aux[K], 
                      readsH: Reads[H], 
                      readsT: Reads[T]): JsResult[FieldType[K, H] :: T] = { 
    val name = witness.value 
    l match { 
     case Nil => JsError() 
     case scala.::(head, tail) => for { 
     h <- readsH.reads(head) 
     t <- /*listToJsResult[K1, H1, T1](tail)*/ readsT.reads(JsArray(tail)) 
     } yield (name ->> h).asInstanceOf[FieldType[K, H]] :: t 
    } 
    } 

    implicit val readsCNil: Reads[CNil] = Reads(_ => throw new Exception) 

    implicit def readHCons[K <: Symbol, H, T <: HList](implicit 
                witness: Witness.Aux[K], 
                readsH: Reads[H], 
                readsT: Reads[T]): Reads[FieldType[K, H] :: T] = 
    Reads { 
     case arr: JsArray => listToJsResult[K, H, T](arr.value.toList) 
     case obj: JsObject => listToJsResult[K, H, T](obj.values.toList) 
     case js => listToJsResult[K, H, T](List(js)) 
    } 


    implicit def readCCons[K <: Symbol, H, T <: Coproduct](implicit 
                 witness: Witness.Aux[K], 
                 readsH: Reads[H], 
                 readsT: Reads[T]): Reads[FieldType[K, H] :+: T] = { 
    val name = witness.value 
    Reads { json => 
     (for { 
     h <- readsH.reads(json) 
     } yield Inl(name ->> h).asInstanceOf[FieldType[K, H] :+: T]) orElse { 
     for { 
      t <- readsT.reads(json) 
     } yield Inr(name ->> t).asInstanceOf[FieldType[K, H] :+: T] 
     } 
    } 
    } 


    implicit def readsGeneric[Repr, A](implicit 
            gen: LabelledGeneric.Aux[A, Repr], 
            readsRepr: Lazy[Reads[Repr]]): Reads[A] = 
    Reads(json => readsRepr.value.reads(json).map(gen.from)) 

    def reads[A](json: JsValue)(implicit readsInst: Reads[A]): JsResult[A] = readsInst.reads(json) 

aber sie scheinen falsch und sie scheinen zu arbeiten, richtig zu arbeiten:

sealed trait MyTrait 
    case class MyClass1(x: Int, y: Int, z: Int) extends MyTrait 
    case class MyClass2(x: Int, y: Int) extends MyTrait 

    reads[MyClass1](JsObject(Seq("x" -> JsNumber(1), "y" -> JsNumber(2), "z" -> JsNumber(3)))) 

//JsSuccess(MyClass1(1,2,3),) 

    reads[MyTrait](JsObject(Seq("x" -> JsNumber(1), "y" -> JsNumber(2), "z" -> JsNumber(3)))) 

//JsSuccess(MyClass1(1,2,3),) 

    reads[MyTrait](JsObject(Seq("x" -> JsNumber(1), "y" -> JsNumber(2)))) 

//JsSuccess(MyClass2(1,2),) 

Die Antwort teilweise auf Bibliothek shapelaysson basiert.

+1

Ich habe gerade eine Antwort geschrieben siehe die Antwort oben – Larousso

0

Ich kann Ihren Code Arbeit wie diese

implicit def readHCons[K <: Symbol, H, T <: HList, R <: HList](implicit 
                   witness: Witness.Aux[K], 
                   readsH: Reads[H], 
                   readsT: Reads[T]): Reads[FieldType[K, H] :: T] = 
    new Reads[FieldType[K, H] :: T] { 
     override def reads(json: JsValue): JsResult[FieldType[K, H] :: T] = { 
     val name = witness.value 
     val jsonH = (__ \ name).read(readsH).reads(json) 
     val jsonT = readsT.reads(json) 
     (jsonH and jsonT) ((a, b) => (name ->> a :: b).asInstanceOf[FieldType[K, H] :: T]) 
     } 
    } 

Aber mein Endziel ist es machen zu können zusaetzliche Regeln hinzufügen: So etwas wie

import validation2.ReadsWithRules._ 
    import play.api.libs.json.Reads._ 
    import play.api.libs.functional.syntax._ 

    val r: Reads[MonPojo] = LabelledGeneric[MonPojo].readsWithRules(('numericField ->> (min(0) keepAnd max(150))) :: HNil) 
    r.reads(Json.obj(
    "stringField" -> "Tata", 
    "numericField" -> 42 
)) 
    println(s"All Reads $r") 

ich mit diesem Code anzupassen versucht

trait ReadsWithRules[T, R <: HList] { 
    def withRules(rules: R): Reads[T] 
    } 

    trait ReadsWithRulesLowerPriority { 

    implicit def readsHNil[R <: HNil]: ReadsWithRules[HNil, R] = new ReadsWithRules[HNil, R] { 
     def withRules(rules: R) = 
     new Reads[HNil] { 
      override def reads(json: JsValue): JsResult[HNil] = JsSuccess(HNil) 
     } 
    } 

    implicit def readHCons[K <: Symbol, H, T <: HList, R <: HList](implicit 
                    witness: Witness.Aux[K], 
                    readsH: Reads[H], 
                    readsT: ReadsWithRules[T, R]): ReadsWithRules[FieldType[K, H] :: T, R] = 
     new ReadsWithRules[FieldType[K, H] :: T, R] { 
     override def withRules(rules: R) = new Reads[FieldType[K, H] :: T] { 
      override def reads(json: JsValue): JsResult[FieldType[K, H] :: T] = { 
      val name = witness.value 
      val jsonH = (__ \ name).read(readsH) 
      val jsonT = readsT.withRules(rules) 
      (jsonH and jsonT) ((a, b) => (name ->> a :: b).asInstanceOf[FieldType[K, H] :: T]).reads(json) 
      } 
     } 
     } 

    } 

    object ReadsWithRules extends ReadsWithRulesLowerPriority { 


    implicit def readHConsWithRule[K <: Symbol, H, T <: HList, R <: HList](implicit 
                    witness: Witness.Aux[K], 
                    at: shapeless.ops.record.Selector.Aux[R, K, Reads[H]], 
                    w: <:<[H, JsValue], 
                    readsH: Reads[H], 
                    readsT: ReadsWithRules[T, R]): ReadsWithRules[FieldType[K, H] :: T, R] = 
     new ReadsWithRules[FieldType[K, H] :: T, R] { 
     override def withRules(rules: R) = new Reads[FieldType[K, H] :: T] { 
      override def reads(json: JsValue): JsResult[FieldType[K, H] :: T] = { 
      val name = witness.value 
      val additionnalRule: Reads[H] = at(rules) 
      val jsonH = (__ \ name).read(readsH).andThen(additionnalRule) 
      val jsonT = readsT 
      (jsonH and jsonT.withRules(rules)) ((a, b) => (name ->> a :: b).asInstanceOf[FieldType[K, H] :: T]).reads(json) 
      } 
     } 
     } 

    implicit def readsGeneric[Repr, A, R <: HList](implicit 
                gen: LabelledGeneric.Aux[A, Repr], 
                readsRepr: Lazy[ReadsWithRules[Repr, R]]): ReadsWithRules[A, R] = 
     new ReadsWithRules[A, R] { 
     override def withRules(rules: R) : Reads[A] = { 
      readsRepr.value.withRules(rules).map(r => gen.from(r)) 
     } 
     } 

    implicit class WithRules[T](gen: LabelledGeneric[T]) { 
     def readsWithRules[R <: HList](rules: R)(implicit readWithRule: ReadsWithRules[T, R]): Reads[T] = { 
     readWithRule.withRules(rules) 
     } 
    } 
    } 

Aber ich habe eine implizite Auflösung Fehler.

Meine frühere Idee war es, die Probleme in Unterschritt zu zersetzen:

  1. Schritt eines T -> Liest [T1] :: Liest [T2] ...

  2. Merge zusaetzliche Regeln in Liest [T1] :: Liest [T2] ...

  3. Sequenz liest [T1] :: Liest [T2] ... => Liest [T1 :: T2 ...]

aber ich kann nicht in Schritt 1 ...

0

ich einen anderen Weg endlich gelingen:

object rules { 

    import play.api.libs.json._ 
    import play.api.libs.functional.syntax._ 
    import scala.annotation.implicitNotFound 
    import shapeless.labelled._ 
    import shapeless.syntax.singleton._ 
    import shapeless.{::, HList, HNil, LabelledGeneric, Lazy, Witness} 
    import shapeless.ops.record.Selector 

    trait SequenceReads[In <: HList] { 
    type Out 

    def apply(in: In): Reads[Out] 
    } 

    object SequenceReads { 

    import play.api.libs.functional.syntax._ 

    type Aux[A <: HList, B <: HList] = SequenceReads[A] {type Out = B} 

    implicit def sequenceHnil[T, R <: HList, TR <: HList](): Aux[HNil, HNil] = new SequenceReads[HNil] { 
     type Out = HNil 

     override def apply(in: HNil): Reads[Out] = { 
     throw new RuntimeException("Oups") 
     } 
    } 

    implicit def sequenceSingleton[T, K <: Symbol](
                implicit witness: Witness.Aux[K] 
               ): Aux[FieldType[K, Reads[T]] :: HNil, T :: HNil] = new SequenceReads[FieldType[K, Reads[T]] :: HNil] { 
     type Out = T :: HNil 

     override def apply(in: FieldType[K, Reads[T]] :: HNil): Reads[T :: HNil] = { 
     val name = witness.value.name 
     (__ \ name).read(in.head).map(_ :: HNil) 
     } 
    } 

    implicit def sequence[T, K <: Symbol, R <: HList, TR <: HList](
                    implicit 
                    witness: Witness.Aux[K], 
                    req: Lazy[SequenceReads.Aux[R, TR]] 
                   ): Aux[FieldType[K, Reads[T]] :: R, T :: TR] = new SequenceReads[FieldType[K, Reads[T]] :: R] { 

     type Out = T :: TR 

     override def apply(in: FieldType[K, Reads[T]] :: R): Reads[Out] = { 
     val name = witness.value.name 
     val head: Reads[T] = (__ \ name).read(in.head) 
     val value: Reads[TR] = req.value.apply(in.tail) 
     (head and value) { 
      _ :: _ 
     } 
     } 
    } 

    implicit class SequenceReadsOps[In <: HList](in: In) { 

     class Builder[Out <: HList] { 
     def apply(
        implicit 
        sequence: SequenceReads.Aux[In, Out] 
       ): Reads[Out] = { 
      sequence(in) 
     } 
     } 

     def sequence[R <: HList](implicit s: SequenceReads.Aux[In, R]) = new Builder[R].apply(s) 
    } 

    } 

    @implicitNotFound("Implicit not found: Rules type or fields are not valid") 
    trait RuleValidation[Repr <: HList, Rules <: HList] 

    object RuleValidation { 

    implicit def validateHNil[Repr <: HList] : RuleValidation[Repr, HNil] = 
     new RuleValidation[Repr, HNil] {} 

    implicit def validateSingleton[Repr <: HList, K <: Symbol, V] (
     implicit 
     sel: Selector.Aux[Repr, K, V] 
    ): RuleValidation[Repr, FieldType[K, Reads[V]] :: HNil] = 
     new RuleValidation[Repr, FieldType[K, Reads[V]] :: HNil] {} 

    implicit def validateHCons[Repr <: HList, H, R <: HList, K <: Symbol, V] (
     implicit 
     sel: Selector.Aux[Repr, K, V], 
     validation: RuleValidation[Repr, R] 
    ): RuleValidation[Repr, FieldType[K, Reads[V]] :: R] = 
     new RuleValidation[Repr, FieldType[K, Reads[V]] :: R] {} 
    } 

    object ReadsWithRules { 



    implicit def readsHNil: Reads[HNil] = new Reads[HNil] { 
     override def reads(json: JsValue): JsResult[HNil] = JsSuccess(HNil) 
    } 


    implicit def readHCons[K <: Symbol, H, T <: HList, R <: HList](implicit 
                    witness: Witness.Aux[K], 
                    readsH: Reads[H], 
                    readsT: Reads[T]): Reads[FieldType[K, H] :: T] = 
     new Reads[FieldType[K, H] :: T] { 
     override def reads(json: JsValue): JsResult[FieldType[K, H] :: T] = { 
      val name = witness.value 
      val jsonH = (__ \ name).read(readsH) 
      val jsonT = readsT 
      (jsonH and jsonT) ((a, b) => (name ->> a :: b).asInstanceOf[FieldType[K, H] :: T]).reads(json) 
     } 
     } 

    implicit def readsGeneric[Repr, A, R <: HList](implicit 
                gen: LabelledGeneric.Aux[A, Repr], 
                readsRepr: Lazy[Reads[Repr]]): Reads[A] = { 
     readsRepr.value.map(r => gen.from(r)) 
    } 
    } 

    trait JsonRead[T] 

    def jsonRead[T]: JsonRead[T] = new JsonRead[T] {} 

    implicit class WithRules[A](gen: JsonRead[A]) { 
    def readsWithRules[R <: HList, K <: Symbol, V, T0 <: HList, ARepr <: HList, AKeys <: HList, RKeys <: HList, Validation <: HList](rules: FieldType[K, V] :: T0)(
     implicit 
     genA: LabelledGeneric.Aux[A, ARepr], 
     readsInst: Reads[A], 
     sequenceReads: SequenceReads[FieldType[K, V] :: T0], 
     validation: RuleValidation[ARepr, FieldType[K, V] :: T0] 
    ): Reads[A] = Reads[A] { json => 
     val valueA: JsResult[A] = readsInst.reads(json) 
     val valueR: JsResult[sequenceReads.Out] = sequenceReads(rules).reads(json) 
     (valueA, valueR) match { 
     case (err1: JsError, err2: JsError) => err1 ++ err2 
     case (err1: JsError, JsSuccess(_, _)) => err1 
     case (JsSuccess(_, _), err2: JsError) => err2 
     case (JsSuccess(v, p), _) => JsSuccess(v, p) 
     } 
    } 
    } 

} 

und der Test

object Test extends App { 

    import play.api.libs.json._ 
    import play.api.libs.json.Reads._ 
    import play.api.libs.functional.syntax._ 
    import shapeless._ 
    import syntax.singleton._ 
    import rules._ 

    case class Other(name: String) 

    case class MonPojo(toto: String, tata: Int, other: Other) 

    object MonPojo { 
    implicit val readsOther = Json.reads[Other] 
    implicit val reads: Reads[MonPojo] = Json.reads[MonPojo] 
    } 


    val strReads = pattern(".*".r) 

    private val value: Reads[MonPojo] = jsonRead[MonPojo].readsWithRules(
    ('tata ->> (min(0) keepAnd max(150))) :: 
     HNil 
) 
    println(s"!!! ${ 
    value.reads(Json.obj(
     "toto" -> "test", 
     "other" -> Json.obj("name" -> "test"), 
     "tata" -> 25 
    )) 
    }") 

} 

Danke für Ihre Hilfe, ich werde Ihre Lösung versuchen.

+0

Liebe @Larousso, großartig, Sie haben endlich Ihre ursprüngliche Idee mit der Sequenzierung umgesetzt. Gern geschehen, es war angenehm, mit Ihnen zu kommunizieren. Danke, dass du meine Antwort akzeptierst. –

Verwandte Themen