-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid use of Java Reflection (restructure part 5) #870
Changes from 58 commits
68678d3
f142baf
b5df752
94f8ea4
f52b936
f7e1cf1
5bceb19
ef05f18
ae72e2d
4d380d3
bb8f592
26a34a9
0697f81
ec38797
028f812
20a1d2c
0630471
062226d
1b302f9
a234f7b
4f3bc44
5c3246e
4ec502d
f75de67
37f81e4
3a15f51
0bd0e17
7c05056
2a15c9a
ce8ea19
5b29925
bf259a3
a3d83b7
71ded79
b84d40f
a278907
4f391e3
d0116bd
6c1e089
22e40de
a0bb16c
8566262
f4cca0c
022fd86
fb47766
c1a97b4
aa12d79
829ec1a
df11cb8
f965e41
55a7f93
a411a12
e328d15
a15daf8
0b134b1
b21dea1
8dde9c0
3cd3ec4
71a93af
1eb35c9
c68759c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,4 @@ | ||
|
||
import scala.language.experimental.macros | ||
import scala.reflect.ClassTag | ||
|
||
package object scalan { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package scalan.reflection | ||
|
||
import scala.collection.compat.immutable.ArraySeq | ||
import scala.collection.mutable | ||
import scala.collection.immutable | ||
|
||
/** Reflection metadata and global dictionaries to access it. */ | ||
object CommonReflection { | ||
/** Descriptors of classes. */ | ||
val classes = mutable.HashMap.empty[Class[_], SRClass[_]] | ||
|
||
/** Registers a class entry in the map of classes. | ||
* | ||
* @tparam T the type of the class to be registered | ||
* @param clazz the class to be registered | ||
* @param constructors the constructors of the class | ||
* @param fields the fields of the class | ||
* @param methods the methods of the class (represented as a map of method names and argument types to the corresponding RMethod instances) | ||
*/ | ||
def registerClassEntry[T](clazz: Class[T], | ||
constructors: Seq[SRConstructor[_]] = ArraySeq.empty, | ||
fields: Map[String, SRField] = Map.empty, | ||
methods: Map[(String, Seq[Class[_]]), RMethod] = Map.empty): Unit = classes.synchronized { | ||
classes.put(clazz, new SRClass(clazz, constructors, fields, methods)) | ||
} | ||
|
||
registerClassEntry(classOf[Boolean]) | ||
|
||
registerClassEntry(classOf[Byte]) | ||
|
||
registerClassEntry(classOf[Short]) | ||
|
||
registerClassEntry(classOf[Int]) | ||
|
||
registerClassEntry(classOf[Long]) | ||
|
||
registerClassEntry(classOf[Product2[_, _]]) | ||
|
||
registerClassEntry(classOf[immutable.$colon$colon[_]], | ||
constructors = Array( | ||
mkConstructor(Array(classOf[java.lang.Object], classOf[immutable.List[_]])) { args => | ||
new immutable.$colon$colon(args(0).asInstanceOf[java.lang.Object], args(1).asInstanceOf[immutable.List[_]]) | ||
} | ||
) | ||
) | ||
|
||
{ val clazz = classOf[scala.Option[_]] | ||
registerClassEntry(clazz, | ||
methods = Map( | ||
mkMethod(clazz, "filter", Array(classOf[scala.Function1[_,_]])) { (obj, args) => | ||
obj.asInstanceOf[Option[Any]].filter(args(0).asInstanceOf[Any => Boolean]) | ||
}, | ||
mkMethod(clazz, "map", Array(classOf[scala.Function1[_,_]])) { (obj, args) => | ||
obj.asInstanceOf[Option[Any]].map(args(0).asInstanceOf[Any => Any]) | ||
} | ||
) | ||
) | ||
} | ||
|
||
{ val clazz = classOf[scala.Some[_]] | ||
registerClassEntry(clazz, | ||
constructors = Array( | ||
mkConstructor(Array(classOf[java.lang.Object])) { args => | ||
new scala.Some(args(0).asInstanceOf[java.lang.Object]) | ||
} | ||
) | ||
) | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package scalan.reflection | ||
|
||
import debox.cfor | ||
import scalan.reflection.memoize | ||
|
||
import java.lang.reflect.{Field, Constructor, Method} | ||
import scala.collection.concurrent.TrieMap | ||
import scala.collection.mutable | ||
|
||
/** | ||
* A class that represents a Java class of type `T`. | ||
* | ||
* @constructor creates a new instance of `JRClass` with the given value. | ||
* @param value the Java class of type `T`. | ||
*/ | ||
class JRClass[T](val value: Class[T]) extends RClass[T] { | ||
|
||
/** A mutable map that stores the fields of this class. */ | ||
val fields = TrieMap.empty[String, RField] | ||
|
||
override def getField(name: String): RField = | ||
memoize(fields)(name, JRField(value.getField(name))) | ||
|
||
/** A mutable map that stores the methods of this class. */ | ||
val methods = TrieMap.empty[(String, Seq[Class[_]]), RMethod] | ||
|
||
override def getMethod(name: String, parameterTypes: Class[_]*): RMethod = { | ||
memoize(methods)((name, parameterTypes), JRMethod(this, value.getMethod(name, parameterTypes:_*))) | ||
} | ||
|
||
override def getSimpleName: String = value.getSimpleName | ||
override def getName: String = value.getName | ||
|
||
/** A sequence that stores the constructors of this class. */ | ||
var constructors: Seq[RConstructor[_]] = _ | ||
|
||
override def getConstructors(): Seq[RConstructor[_]] = { | ||
if (constructors == null) { | ||
synchronized { | ||
if (constructors == null) { | ||
val cs = value.getConstructors.asInstanceOf[Array[Constructor[Any]]] | ||
val buf = mutable.ArrayBuilder.make[RConstructor[Any]] | ||
cfor(0)(_ < cs.length, _ + 1) { i => | ||
val c = cs(i) | ||
buf += JRConstructor[Any](i, c) | ||
} | ||
constructors = buf.result().asInstanceOf[Array[RConstructor[_]]] | ||
} | ||
} | ||
} | ||
constructors | ||
} | ||
|
||
/** Helper method that returns a sequence of `JRConstructor` objects that were at least | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "a sequence of" seems to be excessive here as well There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
* once used at runtime. | ||
*/ | ||
def getUsedConstructors(): Seq[JRConstructor[_]] = | ||
getConstructors().collect { case c: JRConstructor[_] if c.wasUsed => c } | ||
|
||
override def isPrimitive(): Boolean = value.isPrimitive | ||
|
||
override def getSuperclass(): RClass[_ >: T] = RClass(value.getSuperclass) | ||
|
||
override def isAssignableFrom(cls: Class[_]): Boolean = value.isAssignableFrom(cls) | ||
|
||
override def getDeclaredMethods(): Array[RMethod] = value.getDeclaredMethods.map(JRMethod(this, _)) | ||
|
||
override def equals(other: Any): Boolean = (this eq other.asInstanceOf[AnyRef]) || (other match { | ||
case that: JRClass[_] => | ||
val eq = value == that.value | ||
if (!eq) | ||
assert(this.getName != that.getName) // sanity check | ||
eq | ||
case _ => false | ||
}) | ||
|
||
override def hashCode(): Int = value.hashCode() | ||
|
||
override def toString: String = s"JRClass(${value.getName})" | ||
} | ||
|
||
|
||
/** Implements [[RField]] using Java reflection. | ||
* | ||
* @param value The [[java.lang.reflect.Field]] object to wrap. | ||
*/ | ||
class JRField private (val value: Field) extends RField { | ||
override def getType: Class[_] = value.getType | ||
|
||
override def equals(other: Any): Boolean = (this eq other.asInstanceOf[AnyRef]) || (other match { | ||
case that: JRField => value == that.value | ||
case _ => false | ||
}) | ||
override def hashCode(): Int = value.hashCode() | ||
override def toString: String = s"JRField($value)" | ||
} | ||
object JRField { | ||
private[reflection] def apply(field: Field): RField = new JRField(field) | ||
} | ||
|
||
/** Implements [[RConstructor]] using Java reflection. | ||
* | ||
* @tparam T The type of the class that declares this constructor. | ||
* @param index The index of the constructor in the sequence of all constructors of the class. | ||
* @param value The [[java.lang.reflect.Constructor]] to be wrapped. | ||
*/ | ||
class JRConstructor[T] private (val index: Int, val value: Constructor[T]) extends RConstructor[T] { | ||
@volatile var wasUsed: Boolean = false | ||
override def newInstance(initargs: AnyRef*): T = { | ||
wasUsed = true | ||
value.newInstance(initargs:_*) | ||
} | ||
override def getParameterTypes(): Array[Class[_]] = { | ||
wasUsed = true | ||
value.getParameterTypes | ||
} | ||
|
||
override def equals(other: Any): Boolean = (this eq other.asInstanceOf[AnyRef]) || (other match { | ||
case that: JRConstructor[_] => value == that.value | ||
case _ => false | ||
}) | ||
override def hashCode(): Int = value.hashCode() | ||
override def toString: String = s"JRConstructor($index, $value)" | ||
} | ||
object JRConstructor { | ||
private[reflection] def apply[T](index: Int, value: Constructor[T]): RConstructor[T] = new JRConstructor[T](index, value) | ||
} | ||
|
||
/** | ||
* Implements [[RMethod]] using Java reflection. | ||
* | ||
* @param declaringClass The JRClass that declares this method. | ||
* @param value The [[java.lang.reflect.Method]] instance that this JRMethod represents. | ||
*/ | ||
class JRMethod private (declarigClass: JRClass[_], val value: Method) extends RMethod { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. declaringClass There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
override def invoke(obj: Any, args: AnyRef*): AnyRef = { | ||
val name = value.getName | ||
val parameterTypes: Seq[Class[_]] = value.getParameterTypes | ||
memoize(declarigClass.methods)((name, parameterTypes), this) | ||
value.invoke(obj, args:_*) | ||
} | ||
|
||
override def getName: String = value.getName | ||
|
||
override def getDeclaringClass(): Class[_] = value.getDeclaringClass | ||
|
||
override def getParameterTypes(): Seq[Class[_]] = value.getParameterTypes | ||
|
||
override def equals(other: Any): Boolean = (this eq other.asInstanceOf[AnyRef]) || (other match { | ||
case that: JRMethod => value == that.value | ||
case _ => false | ||
}) | ||
|
||
override def hashCode(): Int = value.hashCode() | ||
override def toString: String = s"JRMethod($value)" | ||
} | ||
object JRMethod { | ||
private[reflection] def apply(clazz: JRClass[_], value: Method): RMethod = new JRMethod(clazz, value) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just "Constructors of this class" ? see https://docs.scala-lang.org/style/scaladoc.html#general-style
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed