2015-11-24 13 views
5

Sono nuovo di Shapeless. Ho una classe di supporto che sfrutta l'informe "Derivazione della classe tipografica automatica" (https://gist.github.com/negator/fbbcd1b2ce9a85b762b7) per aiutarmi a popolare le letture e le scritture JSON.Impossibile trovare il valore implicito per il parametro lgen: shapeless.LabelledGeneric.Aux

import play.api.libs._ 
import json._ 

import shapeless.{ `::` => :#:, _ } 
import poly._ 

object SReads extends LabelledTypeClassCompanion[Reads] { 
    object typeClass extends LabelledTypeClass[Reads] { 

    def emptyProduct: Reads[HNil] = Reads(_ => JsSuccess(HNil)) 

    def product[F, T <: HList](name: String, FHead: Reads[F], FTail: Reads[T]) = Reads[F :#: T] { 
     case obj @ JsObject(fields) => 
     for { 
     head <- FHead.reads(obj \ name) 
     tail <- FTail.reads(obj - name) 
     } yield head :: tail 

     case _ => JsError("Json object required") 
     } 

    def project[F, G](instance: => Reads[G], to: F => G, from: G => F) = Reads[F](instance.map(from).reads) 

    def emptyCoproduct: Reads[CNil] = Reads[CNil](_ => JsError("CNil object not available")) 

    def coproduct[L, R <: Coproduct](
     name: String, 
     cl: => Reads[L], 
     cr: => Reads[R]) = Reads[L :+: R]{ js => 

     js match { 
     case js @ JsString(n) if n == name => cl.reads(js).map(Inl.apply) 
     case js @ _      => cr.reads(js).map(Inr.apply) 
     } 
    } 
    } 
} 

Questo è il modo che ho usato:

case class TrialMember(
    @Key("_id") var id: String, 
    var weeks: String, 
    var `type`: Option[String] = Some("email"), 
    var updatedDate: Date = DateTime.now.toDate 
) 

object TrialMemberDao extends ModelCompanion[TrialMember, String] { 
    def collection = mongoCollection("trial_member") 
    val dao = new SalatDAO[TrialMember, String](collection) {} 
    def emails() = dao.find(MongoDBObject("type" -> "email")).toList.map(_.id) 
    def domains() = dao.find(MongoDBObject("type" -> "domain")).toList.map(_.id) 
    def isTrialMember(userEmail: String): Boolean = { 
    val trialMembers = emails() // whitelisted emails 
    val trialDomains = domains() // whitelisted domains 
    trialMembers.contains(userEmail) || 
     trialDomains.filter(userEmail.contains(_)).headOption.isDefined 
    } 

} 

object TrialMember { 
    implicit val jsonWrites: Writes[TrialMember] = SWrites.deriveInstance 
    implicit val jsonReads: Reads[TrialMember] = SReads.deriveInstance 
} 

Ma dopo l'aggiornamento a SBT 0.13.8 and Play 2.4, ora mi dà questo errore:

could not find implicit value for parameter lgen: shapeless.LabelledGeneric.Aux[T,LKV] 
[error] implicit val reads: Reads[TrialMember] = SReads.deriveInstance 
+0

Si prega di fornire la definizione 'Foo'. Sembra funzionare per il mio 'case class' – Odomontois

+0

@Odomontois Ho modificato la domanda. Per favore dai un'occhiata. – angelokh

risposta

1

Il problema è un po 'divertente, il tuo deriver typeclass è perfettamente implementato mentre il compilatore non riesce a trovare l'istanza Reads per Option[String] che dovrebbe essere usata per il campo type. Basta fornire il codice con qualcosa di simile a seguente definizione:

object optionFormats { 
    def noneReads[T]: Reads[Option[T]] = Reads(Function.const(JsSuccess(None))) 

    implicit def optFormat[T](implicit w: Writes[T], r: Reads[T]) = 
    Format[Option[T]](
     r.map[Option[T]](Some(_)).orElse(noneReads), 
     Writes(_.fold[JsValue](JsNull)(w.writes))) 
} 

E poi in ogni codice appena

import optionFormats._ 

E l'istanza dovrebbe essere costruito, se lo desideri.

+0

Dove devo fornire questa linea? L'ho usato nell'oggetto TrialMember e sta funzionando. Ma poi devo farlo in tutte le classi di oggetti. C'è un modo per correggere SReads invece? – angelokh

+0

@Odomontois Sai perché aggiornare a sbt 0.13.8 e giocare a 2.4 significava che il vecchio codice non sarebbe più compilato? – rmin

Problemi correlati