2013-05-12 47 views
9

我想在scala中使用spray-json来识别在转换为Json和返回时Ec2Provider和OpenstackProvider之间的选择。 我希望能够在“提供者”中做出选择,如果这些选择不适合可用的选择,则不应该进行验证。转换多态case类到json并返回

我在这次尝试中可以看到下面的代码:

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

不幸的是,因为它无法找到Provider抽象类格式化失败。

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

任何人有这方面的任何解决方案?

回答

14

你想要做什么,不提供开箱即用(即通过类似类型的提示,使解串器知道具体的类实例化),但它当然可以用一个小的腿工作。首先,例如,通过使用代码的简化版本,上面贴:

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

为了能够序列化抽象类Provider的/反序列化的情况下,我创建了我在哪里提供自定义格式用于读写Provider实例的操作。尽管我正在检查一个简单的条件(二进制,因为只有2个impls Provider),所以我在做这些功能,看看它是什么类型,然后委托给逻辑来处理这种类型。

对于写作,我只需要知道哪个实例类型是容易的。阅读虽然有点棘手。为了阅读,我正在检查对象有多少属性,并且由于这两个impls具有不同数量的道具,我可以区分哪个是这种方式。我在这里所做的检查是非常简单的,但它表明,如果您可以查看Json AST并区分类型,那么您可以选择要反序列化的哪一个。您的实际检查可以按照您的喜好简单或复杂,只要在区分类型时具有确定性即可。

+0

比你非常!这正是我需要的! – wernerb 2013-05-13 15:48:28