Skip to content

Instantly share code, notes, and snippets.

@squito
Last active September 24, 2020 01:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save squito/329d9cd82a21f645d592 to your computer and use it in GitHub Desktop.
Save squito/329d9cd82a21f645d592 to your computer and use it in GitHub Desktop.
utils for accessing field & methods that are private in the scala repl via reflection
/* For example, I want to do this:
*
* sqlContext.catalog.client.getTable("default", "blah").properties
*
* but none of that is public to me in the shell. Using this, I can now do:
*
* sqlContext.reflectField("catalog").reflectField("client").reflectMethod("getTable", Seq("default", "blah")).reflectField("properties")
*
* not perfect, but usable.
*/
import java.lang.reflect.{Field, Method}
def _methods(cls:Class[_]): Seq[Method] = {
if (cls == null) Seq()
else cls.getDeclaredMethods() ++ _methods(cls.getSuperclass())
}
def methods(obj: Any): Seq[String] = {
_methods(obj.getClass()).map(_.getName()).sorted
}
def _fields(cls: Class[_]): Seq[Field] = {
if (cls == null) Seq()
else cls.getDeclaredFields() ++ _fields(cls.getSuperclass())
}
def fields(obj: Any): Seq[String] = {
_fields(obj.getClass()).map(_.getName()).sorted
}
def clzFindMethod(clz: Class[_], name:String): Method = {
// TODO: handle scala's name munging, eg. org$apache$spark$sql$hive$HiveExternalCatalog$$makeQualified
val method = _methods(clz).find(_.getName() == name).get
method.setAccessible(true)
method
}
def findMethod(obj: Any, name:String): Method = {
// TODO: handle scala's name munging, eg. org$apache$spark$sql$hive$HiveExternalCatalog$$makeQualified
clzFindMethod(obj.getClass(), name)
}
def get(obj: Any, name:String): Any = {
val clz = obj.getClass()
_fields(clz).find(_.getName() == name) match {
case Some(f) =>
f.setAccessible(true)
f.get(obj)
case None =>
val m = findMethod(obj, name)
m.invoke(obj)
}
}
def showFields(obj: Any): Unit = {
fields(obj).foreach{println}
}
def showMethods(obj: Any): Unit = {
methods(obj).foreach{println}
}
implicit class StaticReflect(clz: Class[_]) {
def reflectMethod(name: String, args: Seq[Object]): Any = {
clzFindMethod(clz, name).invoke(null, args: _*)
}
}
implicit class Reflector(obj: Any) {
// TODO error msgs
def reflectField(name: String): Any = {
get(obj, name)
}
def reflectMethod(name: String, args: Seq[Object]): Any = {
findMethod(obj,name).invoke(obj, args: _*)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment