从Scala中的类名获取类型

时间:2014-10-21 08:09:09

标签: scala reflection

我想做以下事情:

val factoryType = typeOf[Class.
          forName("com.menith.amw.worksheets." + params("problem") + "ProblemFactory")]
val factory = parse(params("args")).extract[factoryType]

parse方法允许我通过给它一个JSON字符串来获取case类的实例,然后我可以通过将它传递给期望的类型来使用extract方法。但是我在从Class.forName获取类型时遇到了一些问题。

1 个答案:

答案 0 :(得分:2)

可能有效的一个很好的解决方案是进行多态反序列化。这允许你向你的json添加一个字段(比如" type")并允许Jackson(假设你正在使用像杰克逊这样令人敬畏的json解析器)来确定正确的类型你代表。

这个post对多态类型进行了很好的介绍。它涵盖了许多有用的案例,包括您无法修改第三方代码的情况(此处您添加了一个Mixin来注释类型层次结构)。

最简单的情况最终看起来像这样(并且所有这些对Scala对象都有效 - jackson even has a great scala module):

object Test {
  @JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "type"
  )
  @JsonSubTypes(Array(
    new Type(value = classOf[Cat], name = "cat"),
    new Type(value = classOf[Dog], name = "dog")
  ))
  trait Animal

  case class Dog(name: String, breed: String, leash_color: String) extends Animal
  case class Cat(name: String, favorite_toy: String) extends Animal

  def main(args: Array[String]): Unit = {
    val objectMapper = new ObjectMapper with ScalaObjectMapper
    objectMapper.registerModule(DefaultScalaModule)

    val dogStr = """{"type": "dog", "name": "Spike", "breed": "mutt",  "leash_color": "red"}"""
    val catStr = """{"type": "cat", "name": "Fluffy", "favorite_toy": "spider ring"}"""

    val animal1 = objectMapper.readValue[Animal](dogStr)
    val animal2 = objectMapper.readValue[Animal](catStr)

    println(animal1)
    println(animal2)
  }
}

这会生成此输出:

// Dog(Spike,mutt,red)
// Cat(Fluffy,spider ring)

您也可以避免列出子类型映射,但它需要json" type"字段有点复杂。试验它;你可能会喜欢它。像这样定义动物:

@JsonTypeInfo(
  use = JsonTypeInfo.Id.CLASS,
  include = JsonTypeInfo.As.PROPERTY,
  property = "type"
)
trait Animal

它产生(并消耗)json像这样:

/*
{
    "breed": "mutt",
    "leash_color": "red",
    "name": "Spike",
    "type": "classpath.to.Test$Dog"
}
{
    "favorite_toy": "spider ring",
    "name": "Fluffy",
    "type": "classpath.to.Test$Cat"
}
*/