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



如果我错了,请纠正我,但是当使用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 _)

你必须在Play中这样做的原因是框架设计选择,这是一个非常好的选择。

在Play中,该机制依赖于Scala隐式,这是一个非常强大的特性,可以使该机制高度可插拔,在某种意义上,此时您调用:
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序列化依赖于隐式。

你不需要:

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结构与你的对象定义不匹配时,手写的读/写/格式是有用的。

因为您没有提到您指的是哪个JSON/Spring库集成,所以我以JSON通过Jackson/Spring集成为例。我相信它利用了Java Beans字段命名约定。这将涉及到在运行时发生的反射。

但是,Play的Scala Json库提供了Json数据中所有类型的编译时安全性。它也给了你一个很好的函数语法map, flatMap, orElse等。这是一个巨大的优势。

查看更多信息:

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

理论上可以编写带有默认隐式参数的函数,如

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

但是在播放Json的情况下,它不会工作,因为Json。format[T]是一个宏,它不能解析泛型符号T。它只能解析直接引用case类或任何带有unapply的符号。

另一方面,似乎可以编写一个宏来生成与我描述的相同的函数,但不是Apply(Json.format[T]),而是使用来自JsMacroImpl的AST。macroImpl(c, "format",…)。

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

最新更新