2017-08-25 70 views
1

我想做一个玩json从任意使用无形的案例类读取。自定义类型与无遮挡pb与隐式分辨率

眼下我'试图实现后续的使用LabelledGeneric

步骤

从T,我有一个的FieldType [K1,V1] ::的FieldType [K2,V2] :: ...

然后我想建立类型的HList读取[V1] ::读取[V2] ...

这里是代码我'使用:

/* 
    * 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 

是否有人能帮助我吗?

谢谢亚历克斯。

回答

0

这里是实现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

然后我想建立类型的HList读取[V1] ::读取[V2] ...

目前尚不清楚为什么你需要的HList读取,而不是HList的读取(所以我猜你不需要另一种类型的HReads,Reads应该足够了)。我想你需要执行implicits:

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] = ??? 

和类似的两个副产品,如果你需要。

我写了一些实现

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) 

,但他们似乎不正确 工作,他们似乎正常工作:

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),) 

答案是部分地基于库shapelaysson

+1

我刚刚发布了一个答案,请参阅上面的答复 – Larousso

0

我可以让你的代码工作像这样

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]) 
     } 
    } 

但我的最终目标是能够添加其它附加规则:喜欢的东西

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") 

我试图用这个

来适应你的代码
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) 
     } 
    } 
    } 

但我有一个隐式的解析错误。

我以前的想法是分解子步骤的问题:

  1. 步骤1吨 - >读[T1] ::读取[T2] ...

  2. 合并其它附加规则读取[T1] ::读取[T2] ...

  3. 序列读取[T1] ::读取[T2] ... =>读取[T1 :: T2 ...]

但我在第1步失败...

0

我终于成功的另一种方式:

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) 
     } 
    } 
    } 

} 

而且测试

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 
    )) 
    }") 

} 

感谢您的帮助,我会尽力解决您的问题。

+0

亲爱的@Larousso,太棒了,你终于实现了你最初的想法,不客气,与你沟通愉快。感谢您接受我的回答。 –