为什么在java中你不需要创建这些json读/写?

时间:2014-08-21 17:39:49

标签: java scala playframework

如果我错了,请纠正我,但是当使用Java而不是Spring MVC时,你没有必要创建这些额外的类来将你的Java类映射到JSON和JSON到类。

为什么你必须在Play with Scala中这样做?它与Scala有关吗?

case class Location(lat: Double, long: Double)

implicit val locationWrites: Writes[Location] = (
  (JsPath \ "lat").write[Double] and
  (JsPath \ "long").write[Double]
)(unlift(Location.unapply))


implicit val locationReads: Reads[Location] = (
  (JsPath \ "lat").read[Double] and
  (JsPath \ "long").read[Double]
)(Location.apply _)

4 个答案:

答案 0 :(得分:11)

您必须在Play中执行此操作的原因是框架设计选择,这是一个非常好的选择。

在Play中,该机制依赖于 Scala implicits ,这是一个非常强大的功能,可以使机制高度可插入,从而在您调用的那一刻:

Json.toJson(Location(4.5, 5.3)) 

编译器将在匹配所需类型的范围内查找隐式 Scala语言规范描述了解决隐含的算法,并且此类算法的设计方式使您可以在有限范围内“导入”隐式。由于这个功能,在程序的不同部分,您可以看到您的读/写或任何类型类的不同实现。

object MyImplicits {

    object ImplicitJson1{
        implicit val write:Write[Location] = "write to json all fields"
    }

    object ImplicitJson2{
        implicit val write:Write[Location] = "skip field a"
    }
}

object MyBusinessCode{

    def f1(location:Location){
        import MyImplicits.ImplicitJson1._
        Json.toJson(location)
    }
    def f2(location:Location){
        import MyImplicits.ImplicitJson2._
        Json.toJson(location)
    }

    def dynamicChoice(location:Location){
        implicit val write = {
            if(location.isEurope)           
                MyImplicits.ImplicitJson1.write
            else
                MyImplicits.ImplicitJson2.write
        }
        Json.toJson(location)
    }

}

相反,在Spring中,这通常是通过内省和反思来完成的。您可能需要使用注释来帮助Spring确定如何从数据模型构建Json。结果是你不能改变它的完成方式,因此你的灵活性会降低。

由于您可能不需要更多灵活性,因此许多Scala库/框架为您提供了生成所需类型类的默认实现的函数。额外的代码行

implicit val fmt = Json.format[Location]

是您必须支付的价格,因为Play json序列化依赖于隐式。

答案 1 :(得分:1)

您不需要:

case class Location(lat: Double, long: Double)

object Location {

  implicit val fmt = Json.format[Location]

}

Json.toJson(Location(4.5, 5.3)) // returns JsValue

当您的JSON结构与您的对象定义不匹配时,手写的读/写/格式非常有用。

答案 2 :(得分:1)

由于您还没有提到您想要的JSON / Spring库集成,我将通过Jackson / Spring集成来举例说明JSON。我相信它利用了Java Beans字段命名约定。这将涉及反射,并且在运行时发生。

但是,Play的Scala Json库提供了JSON数据中所有类型的编译时安全性。它还为您提供了一个很好的函数语法mapflatMaporElse等。这是一个巨大的优势。

更多信息请参阅此问题:

https://softwareengineering.stackexchange.com/questions/228193/json-library-jackson-or-play-framework

答案 3 :(得分:0)

理论上,可以使用默认隐式参数(如

)编写函数
def toJson[T](x: T)(implicit fmt: Reads[T] = Json.format[T]) = Json.toJson(x)(fmt)

但是在Play Json的情况下,它将无法工作,因为Json.format [T]是一个宏,它无法解析泛型类型符号T.它只能解析直接引用case类的符号或任何unapply的符号(参见sources

另一方面,似乎可以编写一个宏,它生成与我描述的相同的功能,但代替Apply(Json.format [T])使用来自JsMacroImpl.macroImpl的AST(c,&#34) ;格式",...)。

无论如何,它不是语言限制 - 它只是没有在给定的库中实现。