【问题标题】:json4s object extraction with extra data带有额外数据的 json4s 对象提取
【发布时间】:2014-10-17 22:13:33
【问题描述】:

我正在使用带有 json4s 的喷雾,并且我有下面的实现来处理更新对象的 put 请求......我的问题是,我首先从 json 中提取 SomeObject 的实例,但是作为一个RESTful api,我希望在 URL 中指定 ID。因此,我必须以某种方式创建另一个使用 ID 索引的 SomeObject 实例……为此,我使用了像 SomeObject(id: Long, obj: SomeObject) 这样的构造函数。它工作得很好,但实现起来很丑陋,而且感觉效率低下。我该怎么做才能以某种方式将 ID 粘贴在那里,以便我只创建 SomeObject 的一个实例?

class ApplicationRouter extends BaseRouter {
  val routes =
    pathPrefix("some-path") {
      path("destination-resource" \ IntNumber) { id =>
        entity(as[JObject]) { rawData =>
          val extractedObject = rawData.camelizeKeys.extract[SomeObject]
          val extractedObjectWithId = SomeObject(id, extractedObject)
          handleRequest(extractedObjectWithId)
        }
      }
    }
}

case class SomeObject(id: Long, data: String, someValue: Double, someDate: DateTime) {
  def this(data: String, someValue: Double, someDate: DateTime) = this(0, data, someValue, someDate)
  def this(id: Long, obj: SomeObject) = this(id, obj.data, obj.someValue, obj.someDate)
}

【问题讨论】:

    标签: json scala spray case-class json4s


    【解决方案1】:

    在翻阅文档一段时间后,我想出了一个解决方案:

    class ApplicationRouter extends BaseRouter {
      val routes =
        pathPrefix("some-path") {
          path("destination-resource" \ IntNumber) { id =>
            entity(as[JObject]) { rawData =>
              val extractedObject = rawData.camelizeKeys.merge { 
                  ("id", id)
              }.extract[SomeObject]
              handleRequest(extractedObject)
            }
          }
        }
    }
    

    【讨论】:

      【解决方案2】:

      由于没有在所有实例上设置 id 字段,这意味着它是可选的,所以使用Option 类型来指示它。使用 id: Option[Long] 字段定义您的案例类。这使得 json 解析器在 id 字段不存在时跳过它,但允许您在有值时分配一个值。

      case class SomeObject(id: Option[Long], data: String, someValue: Double, someDate: DateTime)
      
      class ApplicationRouter extends BaseRouter {
        val routes =
          pathPrefix("some-path") {
            path("destination-resource" \ IntNumber) { id =>
              entity(as[JObject]) { rawData =>
                val extractedObject = rawData.camelizeKeys.extract[SomeObject]
                val extractedObjectWithId = extractedObject.copy(id = Some(id))
                handleRequest(extractedObjectWithId)
              }
            }
          }
      }
      

      并且不用担心创建新对象会影响性能。它对性能的影响可能比您想象的要小得多。您应该在改进之前衡量性能。

      【讨论】:

      • 如果我没记错的话,ID 不是可选的,但不存在于 JSON 值中,因为它来自不同的来源:URL。换句话说,将id 设为可选在语义上是错误的。
      【解决方案3】:

      我不知道效率,但您可以通过定义一个SomeObjectBuilder 来使您的代码“不那么难看”,您可以将 JSON 值提取到其中。

      case class SomeObjectBuilder(data: String, someValue: Double, someDate: DateTime) {
        def setId(id: Long) = SomeObject(id, data, someValue, someDate)
      }
      
      case class SomeObject(id: Long, data: String, someValue: Double, someDate: DateTime) 
      

      随着提取:

      class ApplicationRouter extends BaseRouter {
        val routes =
          pathPrefix("some-path") {
            path("destination-resource" \ IntNumber) { id =>
              entity(as[JObject]) { rawData =>
                val extractedObject = rawData.camelizeKeys.extract[SomeObjectBuilder]
                val extractedObjectWithId = extractedObject.setId(id)
                handleRequest(extractedObjectWithId)
              }
            }
          }
      }
      

      这样,您没有使用默认的id 设置为零,也就是说,如果我理解正确,永远不会正确。您将其设置为零的唯一原因是提取器不知道该值,因此,使用构建器,您可以显式地进行部分实例化。

      【讨论】:

      • 我真的想不出比这更好的解决方案(尽管我不会在那里使用 setId 作为函数名),但它仍然感觉不对。我希望 scala 有某种方法可以将案例类提取到元组中,然后 scala 可以将该元组的参数作为函数的参数传递。所以它会像SomeObject(id, someObject.toTuple.asParams)一样出来然后scala会使用编译器宏来提取参数,所以它实际上读起来像SomeObject(id, someObject.toTuple._1, someObject.toTuple._2, someObject.toTuple._3)哦,好吧。
      • 由于在提取之前您的 ID 是已知的,因此您还可以定义自定义反序列化器。这是通过扩展CustomSerializer 来完成的,它采用描述反序列化的部分函数。您提到的“元组”听起来很像提供 id 作为此部分函数的闭包。但是,在我看来,实现自定义序列化程序会使代码比手动设置 id 更复杂。
      猜你喜欢
      • 1970-01-01
      • 2015-03-13
      • 1970-01-01
      • 2016-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多