简体   繁体   English

使用Argonaut创建通用JSON转换器

[英]Using Argonaut to create generic JSON converter

I'm new to Scala, and here I'm trying to create a generic json converter based on Argonaut. 我是Scala的新手,在这里我正在尝试创建一个基于Argonaut的通用json转换器。 I've tried to search on google and stackoverflow, but so far I have no clue. 我试图搜索谷歌和stackoverflow,但到目前为止,我没有任何线索。

Here is the snippet of my code. 这是我的代码片段。

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

What I'm trying to do is to generalize such that I don't need to keep adding the match for every new model class (like Currency and Person in this case) that I will add in the future. 我想要做的是概括,以便我不需要为将来添加的每个新模型类(如本例中的Currency和Person)添加匹配项。

Argonaut already has generic encoding and decoding functions. Argonaut已经具有通用编码和解码功能。

For example, Parse.decodeOption will parse a String into any type for which you have a codec. 例如, Parse.decodeOption会将String解析为您拥有编解码器的任何类型。

What you are trying to do is decide at runtime whether you have a codec for a type, but you can make the compiler figure that out for you. 你要做的是在运行时决定你是否有一个类型的编解码器,但你可以让编译器为你解决这个问题。

Whether you can decode to a type T depends on whether there is an implicit instance of DecodeJson[T] in scope. 是否可以解码为类型T取决于范围内是否存在DecodeJson[T]的隐式实例。 (That is a supertype of CodecJson[T] , and you have written a couple of those, so they're good.) (这是CodecJson[T]的超类型,你写了几个,所以它们很好。)

Unfortunately, the compiler won't infer this constraint for you, so you have to mention it in the type signature. 不幸的是,编译器不会为您推断出这个约束,因此您必须在类型签名中提及它。 One way to do this is to use a context bound , which is the T : DecodeJson in the example below. 一种方法是使用上下文绑定 ,这是下面示例中的T : DecodeJson

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

(Also, note that you should really return Option[T] instead of using null .) (另请注意,您应该返回Option[T]而不是使用null 。)

Similarly, write could be implemented with the signature: 同样,可以使用签名实现write

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

Your CodecJson[T] instances are also instances of EncodeJson[T] . CodecJson[T]实例也是实例EncodeJson[T]

you don't need single bean to handle every possible class, you can create a bean for each class, eg 你不需要单个bean来处理每个可能的类,你可以为每个类创建一个bean,例如

class ArgonautConverter[T: CodecJson : ClassTag] extends AbstractHttpMessageConverter[T]    {    
  def supports(clazz) = clazz == classTag[T].runtimeClass
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM