【问题标题】:convert json string to case class object from given json string and type of case class从给定的 json 字符串和案例类的类型将 json 字符串转换为案例类对象
【发布时间】:2020-07-13 16:49:15
【问题描述】:

要求是将json字符串转换为scala中的case类对象,给定jsonString和case类的类型。

我尝试过 Gson 和 jackson 库,但无法解决给定的要求。

package eg.json

import com.fasterxml.jackson.databind.ObjectMapper
import com.google.gson.Gson
import com.typesafe.scalalogging.LazyLogging

case class Person(name : String, age : Int)

case class Address(street : String, buildingNumber : Int, zipCode : Int)

case class Rent(amount : Double, month : String)

//there are many other case classes

object JsonToObject extends LazyLogging{

  import logger._

  def toJsonString(ref : Any) : String = {
    val gson = new Gson()
    val jsonString = gson.toJson(ref)
    jsonString
  }

  def main(args: Array[String]): Unit = {
    val person = Person("John", 35)
    val jsonString = toJsonString(person)

    //here requirement is to convert json string to case class instance, provided the type of case class instance

    val gsonObj = toInstanceUsingGson( jsonString, Person.getClass )
    debug(s"main : object deserialized using gson : $gsonObj")

    val jacksonObj = toInstanceUsingJackson( jsonString, Person.getClass )
    debug(s"main : object deserialized using gson : $jacksonObj")

  }

  def toInstanceUsingGson[T](jsonString : String, caseClassType : Class[T]) : T = {

    val gson = new Gson()
    val ref = gson.fromJson(jsonString, caseClassType)
    ref
  }

  def toInstanceUsingJackson[T](jsonString : String, caseClassType : Class[T]) : T = {

    val mapper = new ObjectMapper()
    val ref = mapper.readValue(jsonString, caseClassType)
    ref
  }
}

上述代码的执行输出是:-

01:32:52.369 [main] DEBUG eg.json.JsonToObject$ - main : object deserialized using gson : Person
Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "name" (class eg.json.Person$), not marked as ignorable (0 known properties: ])
 at [Source: (String)"{"name":"John","age":35}"; line: 1, column: 10] (through reference chain: eg.json.Person$["name"])
    at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:60)
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:822)
    at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1152)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1589)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1567)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:294)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004)
    at eg.json.JsonToObject$.toInstanceUsingJackson(JsonToObject.scala:49)
    at eg.json.JsonToObject$.main(JsonToObject.scala:34)
    at eg.json.JsonToObject.main(JsonToObject.scala)

请建议,如何使用 gson 或 jackson 来实现这一点,或者建议其他一些带有示例示例的库。

以上简化的问题在 github 上:-

https://github.com/moglideveloper/JsonToScalaObject

【问题讨论】:

    标签: json scala jackson gson case-class


    【解决方案1】:

    尝试使用 Cats 的 circe。

    • 将 circe 添加到您的项目中(https://circe.github.io/circe/ - 快速入门)。
    • 创建一个案例类,代表您希望从 json 构建的内容。
    • 声明一个解码器

    https://circe.github.io/circe/codecs/semiauto-derivation.html https://github.com/circe/circe

    import io.circe.parser.decode
    import io.circe.syntax._
    
    case class DataToDecode(name : String,
                            age : Int,
                            street : String,
                            buildingNumber : Int,
                            zipCode : Int, 
                            amount : Double, 
                            month : String)
    object DataToDecode{
    implicit val dataToDecode: Decoder[DataToDecode] = deriveDecoder
    
    def decodeData(data: Json) : DataToDecode {
      data.as[DataToDecode].right.get
      }
    }
    

    很好的例子here

    【讨论】:

    • 怎么样,我会传DataToDecode,为data.as[DataToDecode].right.get。因为将 jsonString 转换为对象的方法可以为任何案例类传递 json 字符串。如何使这个通用
    • 有没有办法让 decodeData 方法对任何案例类都通用
    • 您可以创建一个案例类的案例类 - 但您必须为每个案例类创建一个解码器并将其包含在最终的案例类伴随对象中。
    • 哦,我知道了。谢谢
    【解决方案2】:

    有了杰克逊,你可以这样做:

    import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
    
    val mapper = new ObjectMapper() with ScalaObjectMapper
    //this line my be needed depending on your case classes
    mapper.registerModule(DefaultScalaModule)
    
    def fromJson[T](json: String)(implicit m: Manifest[T]): T = {
        mapper.readValue[T](json)
      }
    
    

    我认为 Jackson 库真的很干净。 用法是这样的:

    val json: String = ???
    val personObject: Person = fromJson[Person](json)
    

    【讨论】:

    • 如何,我将传递 Person,for fromJson[Person](json)。因为将 jsonString 转换为对象的方法可以为任何案例类传递 json 字符串。如何使这个通用
    • @mogli 它是通用的,你通过任何案例类,我只是举一个如何使用它的例子。
    • 哦,我知道了。谢谢
    猜你喜欢
    • 2017-11-14
    • 1970-01-01
    • 1970-01-01
    • 2022-01-03
    • 2016-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-03
    相关资源
    最近更新 更多