2013-05-12 30 views
9

Json'a ve arkaya dönüştürürken Ec2Provider ve OpenstackProvider arasındaki seçimi tanımak için spray-json'u scala'da kullanmaya çalışıyorum. "Sağlayıcı" bölümünde seçimler yapmak istiyorum ve eğer bu seçenekler mevcut olanlara uymuyorsa doğrulanmamalıdır. ŞunaPolimorfik vaka sınıflarını json'a dönüştürün ve geri

girişimim aşağıdaki kodda görülebilir: o Provider soyut sınıf için birformatlayıcı bulamadığından

import spray.json._ 
import DefaultJsonProtocol._ 

case class Credentials(username: String, password: String) 
abstract class Provider 
case class Ec2Provider(endpoint: String,credentials: Credentials) extends Provider 
case class OpenstackProvider(credentials: Credentials) extends Provider 
case class Infrastructure(name: String, provider: Provider, availableInstanceTypes: List[String]) 
case class InfrastructuresList(infrastructures: List[Infrastructure]) 

object Infrastructures extends App with DefaultJsonProtocol { 
    implicit val credFormat = jsonFormat2(Credentials) 
    implicit val ec2Provider = jsonFormat2(Ec2Provider) 
    implicit val novaProvider = jsonFormat1(OpenstackProvider) 
    implicit val infraFormat = jsonFormat3(Infrastructure) 
    implicit val infrasFormat = jsonFormat1(InfrastructuresList) 

    println(
    InfrastructuresList(
     List(
     Infrastructure("test", Ec2Provider("nova", Credentials("user","pass")), List("1", "2")) 
    ) 
    ).toJson 
) 
} 

Ne yazık ki, başarısız olur.

test.scala:19: could not find implicit value for evidence parameter of type Infrastructures.JF[Provider] 

Bunun için herhangi bir çözümü olan var mı?

cevap

14

Ne yapmak istediğiniz, kutudan çıkarılabilir (yani, destansizörün somut sınıfın somut sınıfını tanımasını sağlayan tip ipuçları gibi bir şeyle değil), ancak küçük bir bacak çalışmasıyla kesinlikle mümkündür. İlk olarak, örnek kod basitleştirilmiş bir sürümünü kullanarak yukarıda yayınlanmıştır:

case class Credentials(user:String, password:String) 
abstract class Provider 
case class Ec2Provider(endpoint:String, creds:Credentials) extends Provider 
case class OpenstackProvider(creds:Credentials) extends Provider 
case class Infrastructure(name:String, provider:Provider) 

object MyJsonProtocol extends DefaultJsonProtocol{ 
    implicit object ProviderJsonFormat extends RootJsonFormat[Provider]{ 
    def write(p:Provider) = p match{ 
     case ec2:Ec2Provider => ec2.toJson 
     case os:OpenstackProvider => os.toJson 
    } 

    def read(value:JsValue) = value match{ 
     case obj:JsObject if (obj.fields.size == 2) => value.convertTo[Ec2Provider] 
     case obj:JsObject => value.convertTo[OpenstackProvider] 
    } 
    } 

    implicit val credFmt = jsonFormat2(Credentials) 
    implicit val ec2Fmt = jsonFormat2(Ec2Provider) 
    implicit val openStackFmt = jsonFormat1(OpenstackProvider) 
    implicit val infraFmt = jsonFormat2(Infrastructure) 
} 

object PolyTest { 
    import MyJsonProtocol._ 

    def main(args: Array[String]) { 
    val infra = List(
     Infrastructure("ec2", Ec2Provider("foo", Credentials("me", "pass"))), 
     Infrastructure("openstack", OpenstackProvider(Credentials("me2", "pass2"))) 
    ) 
    val json = infra.toJson.toString 
    val infra2 = JsonParser(json).convertTo[List[Infrastructure]] 
    println(infra == infra2) 
    } 
} 

soyut sınıfın Provider arasında/serisi kaldırılmaya örneklerini seri hale edebilmek amacıyla, ben tedarik ediyorum özel bir biçimlendirici oluşturduk Provider örneklerini okuma ve yazma işlemleri. Bu fonksiyonlarda yaptığım tek şey, ne tür olduğunu görmek ve daha sonra bu türle başa çıkmak için mantığa delege etmek için basit bir koşulu (Provider sadece 2 impels olduğu gibi burada ikili) kontrol ediyor.

Yazmak için, hangi örnek türünün kolay olduğunu bilmem gerekiyor. Okuma biraz zor olsa da. Okumak için, nesnenin kaç tane mülk olduğunu kontrol ediyorum ve iki imparatorluktan farklı sayıda aksesuara sahip olduğundan, hangisinin bu şekilde olduğunu ayırt edebilirim. Burada yaptığım kontrol çok basit, fakat Json AST'ye bakıp türleri ayırt ederseniz, hangisinin seri hale getirileceğini seçebilirsiniz. Fiili çekiniz, türleri ayırt etmede deterministik olduğu sürece, istediğiniz kadar basit veya karmaşık olabilir.

+0

Sizden çok daha fazlası! Bu tam olarak ihtiyacım olan şey! – wernerb