json - 使用Argonaut创建通用JSON转换器

标签 json scala generics argonaut

我是Scala的新手,在这里我试图创建一个基于Argonaut的通用json转换器。我试图在google和stackoverflow上进行搜索,但是到目前为止我还没有头绪。

这是我的代码片段。

import org.springframework.http.converter.AbstractHttpMessageConverter
import org.springframework.http.{MediaType, HttpInputMessage, HttpOutputMessage}    
import scala.io.Source
import argonaut._,Argonaut._

case class Currency(code: String)
object Currency {
    implicit def CurrencyCodecJson: CodecJson[Currency] = casecodec1(Currency.apply, Currency.unapply)("code")
}

case class Person(firstName: String, lastName: String)
object Person {
    implicit def PersonCodecJson: CodecJson[Person] = casecodec2(Person.apply, Person.unapply)("firstName", "LastName")
}

class ArgonautConverter extends AbstractHttpMessageConverter[Object](new MediaType("application", "json", Charset.forName("UTF-8")), new MediaType("application", "*+json", Charset.forName("UTF-8"))) {
    val c = classOf[Currency]
    val p = classOf[Person]

    def writeInternal(t: Object, outputStream: OutputStream) = {
        val jsonString = t match {
            case c:Currency => c.asJson.ToString()
            case p:Person => p.asJson.ToString()
    }

    def supports(clazz: Class[_]): Boolean = clazz.isAssignableFrom(classOf[CodecJson])// clazz == classOf[Currency] || clazz == classOf[LegalEntity]

    def readInternal(clazz: Class[_ <: Object], inputStream: InputStream): Object = {
        val jsonString = Source.fromInputStream(inputStream).getLines.mkString
        val jsonObject = clazz match {
            case `c` => jsonString.decodeOption[Currency]
            case `p` => jsonString.decodeOption[Person]
        }
        jsonObject match {
            case Some(j) => j
            case None => null
        }
    }
}


我想做的是概括一下,这样我就不必继续为将来要添加的每个新模型类(例如,Currency和Person)添加匹配项。

最佳答案

Argonaut已经具有通用的编码和解码功能。

例如,Parse.decodeOption会将一个String解析为您拥有编解码器的任何类型。

您想要做的是在运行时确定是否有某种类型的编解码器,但是您可以让编译器自己弄清楚。

是否可以解码为T类型取决于范围内是否存在DecodeJson[T]的隐式实例。 (这是CodecJson[T]的超类型,您已经编写了其中的几个,所以它们很好。)

不幸的是,编译器不会为您推断此约束,因此您必须在类型签名中提及它。一种方法是使用上下文绑定,在下面的示例中为T : DecodeJson

def read[T : DecodeJson](inputStream: InputStream): Option[T] = {
  val jsonString = Source.fromInputStream(inputStream).getLines.mkString
  Parse.decodeOption(jsonString)
}


(此外,请注意,您应该真正返回Option[T]而不是使用null。)

类似地,write可以通过签名实现:

def write[T : EncodeJSON](t: T, outputStream: OutputStream)


您的CodecJson[T]实例也是EncodeJson[T]的实例。

关于json - 使用Argonaut创建通用JSON转换器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20897157/

相关文章:

generics - 在不固定 `Fn` 参数之一的情况下,在结构定义上指定 `Fn` trait bound

java - 使用gson解析不同类型的Json对象

javascript - 如何在 JavaScript 中解析 JSON?

java - Scala 从 1.9 到 2.1 中的 Jackson 注释被破坏

scala - 如何强制 F[_] 成为 Monad 的实例

scala - 我可以使用 SBT 从其目录中组装一个子项目吗?

java - 如何使用 Java 反射来检查给定类是否实现了 Iterable<? extends T>,对于任何给定的 T

java - 具有相同泛型参数的重载方法?

python - 将大型 JSON 数组写入文件

javascript - 如何将 JSON 从 Web 服务发送到 iOS 项目中的 javascript?