Last active
September 24, 2020 01:09
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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