我需要一些提示来编写一个可以读取json文件并在运行时创建一个case类的scala程序。作为一个例子,如果我们有像json类 -
Employ{
name:{datatype:String, null:false}
age:{datatype:Int, null:true}
Address:{city: {datatype: String, null:true}, zip: {datatype: String, null:false}}
}
这应该创建类似
的类case class Employ(name: String, age: Option[Int], address: Address}
case class Address(city: Option[String], zip:String}
是否可以在scala中执行此操作?
答案 0 :(得分:3)
是的,您可以使用TreeHugger轻松实现此目的。我为我的一个工作项目做了类似的事情。
下面是一个产生Scala Akka Actor类的玩具示例。它需要清理,但希望你能得到这个想法:
import argonaut.Argonaut._
import argonaut._
import org.scalatest.FunSuite
import treehugger.forest._
import definitions._
import treehuggerDSL._
class ConvertJSONToScalaSpec extends FunSuite {
test("read json") {
val input =
"""
|{
| "rulename" : "Rule 1",
| "condition" : [
| {
| "attribute" : "country",
| "operator" : "eq",
| "value" : "DE"
| }
| ],
| "consequence" : "route 1"
|}
""".stripMargin
val updatedJson: Option[Json] = input.parseOption
val tree =
BLOCK(
IMPORT(sym.actorImports),
CLASSDEF(sym.c).withParents(sym.d, sym.e) :=
BLOCK(
IMPORT(sym.consignorImport, "_"),
DEFINFER(sym.methodName) withFlags (Flags.OVERRIDE) := BLOCK(
CASE(sym.f DOT sym.methodCall APPLY (REF(sym.mc))) ==>
BLOCK(
sym.log DOT sym.logmethod APPLY (LIT(sym.logmessage)),
(IF (sym.declaration DOT sym.header DOT sym.consignor DOT sym.consignoreTID ANY_== LIT(1))
THEN (sym.sender APPLY() INFIX ("!", LIT(sym.okcm)))
ELSE
(sym.sender APPLY() INFIX ("!", LIT(sym.badcm)))
)
)
)
)
) inPackage (sym.packageName)
}
基本上你需要做的就是弄清楚如何使用TreeHugger宏;每个宏代表Scala中的特定关键字。它为您提供了一种类型安全的元编程方法。
还有Scala Meta,但我还没有用过它。
答案 1 :(得分:2)
嗯...假设您使用了treehugger
或scala meta
等其他库来生成案例类的代码字符串。现在您可以采取多种方法。要从其中一个开始,您可以执行以下操作。
// import the current runtime mirror as cm
import scala.reflect.runtime.{currentMirror => cm}
// you case code string
val codeString = """
case class Address(city: Option[String], zip:String)
Address(Some("CityName"), "zipcode")
"""
// get the toolbox from mirror
val tb = cm.mkToolBox()
// use tool box to convert string to Tree
val codeTree = tb.parse(codeString)
// eval your tree
val address = tb.eval(codeTree)
问题是val address
的类型为Any
。此外,Universe仍然不知道类型Address
,因此您将无法执行address.asInstanceOf[Address]
。
您可以通过探索有关ClassSymbol
和ClassLoader
的内容来解决这个问题,如果有足够的运气可以解决更多有关Scala和Java中的反射如何工作的问题。但这将是一项艰巨的努力,并不能保证成功之路。