尝试使用Jackson通过scala读取参数化类型的值

2ul0zpep  于 2023-02-16  发布在  Scala
关注(0)|答案(2)|浏览(419)

我正在尝试编写一个方法,允许JacksonObjectMapper将json字符串上的readValue转换为参数化对象类型。

case class MyObj(field1: String, field2: String)

val objectMapper: ObjectMapper = new ObjectMapper().registerModule(new DefaultScalaModule)

def fromJson[T](jsonString: String, objTyp: T): T = {

    objectMapper.readValue(jsonString, classOf[T])

}

val x = fromJson("""{"field1": "something", "field2": "something"}""", MyObj)

这当然会返回错误

class type required but T found

我已经看过这个问题Scala classOf for type parameter,但它似乎没有帮助.它似乎像这是可能的做不知何故.寻找任何帮助

vlurs2pr

vlurs2pr1#

您必须为它提供要解析到的实际运行时类,而不仅仅是一个类型参数。
一种方法是直接传递类:

def fromJson[T](json: String, clazz: Class[T]) = objectMapper.readValue[T](json, clazz)

val x = fromJson("""...""", classOf[MyObj])

或者,您可以使用ClassTag,它在实现中看起来有点混乱,但在调用点上更漂亮:

def fromJson[T : ClassTag](json: String): T = objectMapper.readValue[T](
  json, 
  implicitly[ClassTag[T]].runtimeClass.asInstanceOf[Class[T]]
)

val x = fromJson[MyObj]("""{"field1": "something", "field2": "something"}""")
8yparm6h

8yparm6h2#

我看过这个问题Scala classOf for type parameter,但它似乎没有帮助.
在第一个answer中,它被写成classTag[T].runtimeClass作为classOf[T]的替代,这应该会有帮助。
关于签名

def fromJson[T](jsonString: String, objTyp: T): T

您应该注意到MyObj具有类型MyObj.type(伴随对象类型),而不是MyObj(大小写类类型)。
Class companion object vs. case class itself
如果你调用fromJson("""...""", MyObj)那么这两个地方的类型

def fromJson[...](jsonString: String, objTyp: ???): ???
                                              ^^^   ^^^  <--- HERE

不可能是原来的样子。
如果你能打个电话

fromJson("""...""", classOf[MyObj])

fromJson[MyObj]("""...""")

(通常应该足够了)然后请参见@Dima的answer,你应该更喜欢这些选项,它们更容易。
为了以防万一,如果您真的想像fromJson("""...""", MyObj)那样调用,那么例如,您可以使用type类ToCompanion(这更复杂)
Invoke construcotr based on passed parameter
Get companion object of class by given generic type Scalaanswer

// ToCompanion should be defined in a different subproject

def fromJson[C, T](jsonString: String, objTyp: C)(implicit
  toCompanion: ToCompanion.Aux[C, T],
  classTag: ClassTag[T]
): T =
  objectMapper.readValue(jsonString, classTag.runtimeClass.asInstanceOf[Class[T]])

val x = fromJson("""{"field1": "something", "field2": "something"}""", MyObj)
// MyObj(something,something)

相关问题