Skip to content

Commit

Permalink
add org.json4s.Compat. avoid reflection
Browse files Browse the repository at this point in the history
  • Loading branch information
xuwei-k committed May 5, 2020
1 parent afedbc4 commit 4b2187a
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 46 deletions.
15 changes: 15 additions & 0 deletions core/src/main/scala-2.13+/org/json4s/Compat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.json4s

import scala.language.reflectiveCalls

private[json4s] object Compat {
def makeCollection(clazz: Class[_], array: Array[_]): Option[Any] = {
reflect.ScalaSigReader.companions(clazz.getName).flatMap(_._2).map { c =>
val builder = c
.asInstanceOf[ {def newBuilder: collection.mutable.Builder[Any, Any]}]
.newBuilder
builder ++= array
builder.result
}
}
}
11 changes: 11 additions & 0 deletions core/src/main/scala-2.13-/org/json4s/Compat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.json4s

import scala.language.reflectiveCalls

private[json4s] object Compat {
def makeCollection(clazz: Class[_], array: Array[_]): Option[Any] = {
reflect.ScalaSigReader.companions(clazz.getName).flatMap(_._2).map {
_.asInstanceOf[ {def apply(elems: collection.Seq[_]): Any}].apply(array.toSeq)
}
}
}
50 changes: 4 additions & 46 deletions core/src/main/scala/org/json4s/Extraction.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,13 @@ import scala.reflect.Manifest
import scala.reflect.NameTransformer.encode
import scala.collection.JavaConverters._
import scala.util.Try
import scala.util.Properties
import scala.util.control.NonFatal

/** Function to extract values from JSON AST using case classes.
*
* See: ExtractionExamples.scala
*/
object Extraction {

private[this] val scala213: Double = 2.13

private[this] val currentScalaVersion: Double = 2.13

private[this] val scalaVersion: Double = try {
Properties.scalaPropOrNone("version.number").map {
_.split("""\.""").take(2).mkString(".").toDouble
}.getOrElse(currentScalaVersion)
} catch {
case NonFatal(e) =>
e.printStackTrace()
currentScalaVersion
}

/** Extract a case class from JSON.
* @see org.json4s.JsonAST.JValue#extract
* @throws MappingException is thrown if extraction fails
Expand Down Expand Up @@ -482,36 +466,10 @@ object Extraction {
else if (tpe.erasure == classOf[java.util.ArrayList[_]]) mkCollection(a => new java.util.ArrayList[Any](a.toList.asJavaCollection))
else if (tpe.erasure.isArray) mkCollection(mkTypedArray)
else {
def getCompanion(className: String): Option[Any] = {
val c = try {
Some(Class.forName(className).isAssignableFrom(tpe.erasure))
} catch {
case _: ClassNotFoundException =>
None
}
c.flatMap { _ =>
reflect.ScalaSigReader.companions(tpe.erasure.getName).flatMap(_._2)
}
}

import language.reflectiveCalls

getCompanion("scala.collection.generic.GenericTraversableTemplate") match {
case Some(c) if scalaVersion < scala213 =>
val companion = c.asInstanceOf[{def apply(elems: collection.Seq[_]): Any}]
mkCollection(a => companion(a.toSeq))
case _ =>
getCompanion("scala.collection.Factory") match {
case Some(c) =>
val companion = c.asInstanceOf[{def newBuilder: collection.mutable.Builder[Any, Any]}]
mkCollection{ a =>
val b = companion.newBuilder
b ++= a
b.result
}
case _ =>
fail("Expected collection but got " + tpe)
}
mkCollection{ array =>
Compat.makeCollection(tpe.erasure, array).getOrElse(fail(
"Expected collection but got " + tpe
))
}
}
}
Expand Down

0 comments on commit 4b2187a

Please sign in to comment.