I defined the case class dynamically using Toolbox. And when I do extract of json4s, I get the following exception:
import org.json4s._
import scala.reflect.runtime._
import scala.tools.reflect.ToolBox
implicit val formats = DefaultFormats
val cm = universe.runtimeMirror(getClass.getClassLoader)
val toolBox = cm.mkToolBox()
val parse =
toolBox.parse(
s"""
| case class Person( name:String, age:String)
| scala.reflect.classTag[ Person].runtimeClass
""".stripMargin)
val person = toolBox.compile( parse)().asInstanceOf[Class[_]]
val js = JsonMethods.parse("""{ "name":"Tom","age" : "28"}""")
val jv = js.extract[person.type ] //How do I pass the class type?
**"Exception in thread "main" org.json4s.MappingException: No constructor for type Class, JObject(List((name,JString(Tom)), (age,JString(28))))"**
But after creating a dummy instance of the dynamically created class, Then pass in the type of that dummy class and it will be parsed.
I don't know why. How can I parse without creating a dummy instance?
import org.json4s._
import scala.reflect.runtime._
import scala.tools.reflect.ToolBox
implicit val formats = DefaultFormats
val cm = universe.runtimeMirror(getClass.getClassLoader)
val toolBox = cm.mkToolBox()
val parse =
toolBox.parse(
s"""
| case class Person( name:String, age:String)
| scala.reflect.classTag[ Person].runtimeClass
""".stripMargin)
val person = toolBox.compile( parse)().asInstanceOf[Class[_]]
val dummy = person.getConstructors.head.newInstance( "a", "b") //make dummy instance
val js = JsonMethods.parse("""{ "name":"Tom","age" : "28"}""")
println( js.extract[ dummy.type ] ) // Result: Person(Tom,28)
x.type
is a singleton type. So person.type
can't be correct, it's the singleton type of this specific variable val person: Class[_]
.
Fortunately, dummy.type
is correct because of the runtime reflection. This works even for ordinary case class
import org.json4s._
import org.json4s.jackson.JsonMethods
implicit val formats = DefaultFormats
case class Person(name: String, age: String)
val js = JsonMethods.parse("""{ "name":"Tom","age" : "28"}""")
val dummy0: AnyRef = Person("a", "b")
val dummy: AnyRef = dummy0
js.extract[dummy.type] // Person(Tom,28)
Actually after resolving implicits js.extract[Person]
is
js.extract[Person](formats, ManifestFactory.classType(classOf[Person])
js.extract[dummy.type]
is
js.extract[dummy.type](formats, ManifestFactory.singleType(dummy))
So for a toolbox-generated case class we could try
import org.json4s._
import org.json4s.jackson.JsonMethods
import scala.reflect.ManifestFactory
import scala.reflect.runtime.universe
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val cm = universe.runtimeMirror(getClass.getClassLoader)
val toolBox = cm.mkToolBox()
implicit val formats = DefaultFormats
val person = toolBox.eval(q"""
case class Person(name:String, age:String)
scala.reflect.classTag[Person].runtimeClass
""").asInstanceOf[Class[_]]
val js = JsonMethods.parse("""{ "name":"Tom","age" : "28"}""")
js.extract(formats, ManifestFactory.classType(person))
// java.lang.ClassCastException: __wrapper$1$6246735221dc4d64a9e372a9d0891e5e.__wrapper$1$6246735221dc4d64a9e372a9d0891e5e$Person$1 cannot be cast to scala.runtime.Nothing$
( toolBox.eval(tree)
is instead of toolBox.compile(toolBox.parse(string))()
)
but this doesn't work.
Manifest should be captured from toolbox compile time
import org.json4s._
import org.json4s.jackson.JsonMethods
import scala.reflect.runtime.universe
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val cm = universe.runtimeMirror(getClass.getClassLoader)
val toolBox = cm.mkToolBox()
implicit val formats = DefaultFormats
val person = toolBox.eval(q"""
case class Person(name:String, age:String)
val clazz = scala.reflect.classTag[Person].runtimeClass
scala.reflect.ManifestFactory.classType(clazz)
""").asInstanceOf[Manifest[_]]
val js = JsonMethods.parse("""{ "name":"Tom","age" : "28"}""")
js.extract(formats, person) // Person(Tom,28)
Alternatively you don't need java-reflection Class
at all. You can do
import scala.reflect.runtime
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val cm = runtime.currentMirror
val toolBox = cm.mkToolBox()
toolBox.eval(q"""
import org.json4s._
import org.json4s.jackson.JsonMethods
implicit val formats = DefaultFormats
case class Person(name: String, age: String)
val js = JsonMethods.parse(${"""{"name":"Tom","age" : "28"}"""})
js.extract[Person]
""") // Person(Tom,28)
or
import org.json4s._
import org.json4s.jackson.JsonMethods
import scala.reflect.runtime
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
object Main extends App {
val cm = runtime.currentMirror
val toolBox = cm.mkToolBox()
implicit val formats = DefaultFormats
val person: ClassSymbol = toolBox.define(q"case class Person(name: String, age: String)")
val js = JsonMethods.parse("""{"name":"Tom","age" : "28"}""")
val jv = toolBox.eval(q"""
import Main._
js.extract[$person]
""")
println(jv) // Person(Tom,28)
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.