aboutsummaryrefslogtreecommitdiff
path: root/kamon-core/src/main/scala/kamon/util
diff options
context:
space:
mode:
authorIvan Topolnjak <ivantopo@gmail.com>2017-06-18 12:38:09 +0200
committerIvan Topolnjak <ivantopo@gmail.com>2017-06-18 12:38:09 +0200
commit1d98b9e8a397acf8b6f6f55a3fd5189eb72740ba (patch)
treeb97f219f1714756672310be61b132015a024944a /kamon-core/src/main/scala/kamon/util
parent9119413d8dc9b26874e85d8a5f3b135379b9f6da (diff)
downloadKamon-1d98b9e8a397acf8b6f6f55a3fd5189eb72740ba.tar.gz
Kamon-1d98b9e8a397acf8b6f6f55a3fd5189eb72740ba.tar.bz2
Kamon-1d98b9e8a397acf8b6f6f55a3fd5189eb72740ba.zip
add DynamicAccess utility
Diffstat (limited to 'kamon-core/src/main/scala/kamon/util')
-rw-r--r--kamon-core/src/main/scala/kamon/util/DynamicAccess.scala56
1 files changed, 56 insertions, 0 deletions
diff --git a/kamon-core/src/main/scala/kamon/util/DynamicAccess.scala b/kamon-core/src/main/scala/kamon/util/DynamicAccess.scala
new file mode 100644
index 00000000..87f7024a
--- /dev/null
+++ b/kamon-core/src/main/scala/kamon/util/DynamicAccess.scala
@@ -0,0 +1,56 @@
+package kamon.util
+
+import scala.collection.immutable
+import java.lang.reflect.InvocationTargetException
+import scala.reflect.ClassTag
+import scala.util.Try
+
+/**
+ * Utility class for creating instances from a FQCN, see [1] for the original source.
+ *
+ * It uses reflection to turn fully-qualified class names into `Class[_]` objects and creates instances from there
+ * using `getDeclaredConstructor()` and invoking that.
+ *
+ * [1] https://github.com/akka/akka/blob/master/akka-actor/src/main/scala/akka/actor/ReflectiveDynamicAccess.scala
+ */
+class DynamicAccess(val classLoader: ClassLoader) {
+
+ def getClassFor[T: ClassTag](fqcn: String): Try[Class[_ <: T]] =
+ Try[Class[_ <: T]]({
+ val c = Class.forName(fqcn, false, classLoader).asInstanceOf[Class[_ <: T]]
+ val t = implicitly[ClassTag[T]].runtimeClass
+ if (t.isAssignableFrom(c)) c else throw new ClassCastException(t + " is not assignable from " + c)
+ })
+
+ def createInstanceFor[T: ClassTag](clazz: Class[_], args: immutable.Seq[(Class[_], AnyRef)]): Try[T] =
+ Try {
+ val types = args.map(_._1).toArray
+ val values = args.map(_._2).toArray
+ val constructor = clazz.getDeclaredConstructor(types: _*)
+ constructor.setAccessible(true)
+ val obj = constructor.newInstance(values: _*)
+ val t = implicitly[ClassTag[T]].runtimeClass
+ if (t.isInstance(obj)) obj.asInstanceOf[T] else throw new ClassCastException(clazz.getName + " is not a subtype of " + t)
+ } recover { case i: InvocationTargetException if i.getTargetException ne null ⇒ throw i.getTargetException }
+
+ def createInstanceFor[T: ClassTag](fqcn: String, args: immutable.Seq[(Class[_], AnyRef)]): Try[T] =
+ getClassFor(fqcn) flatMap { c ⇒ createInstanceFor(c, args) }
+
+ def getObjectFor[T: ClassTag](fqcn: String): Try[T] = {
+ val classTry =
+ if (fqcn.endsWith("$")) getClassFor(fqcn)
+ else getClassFor(fqcn + "$") recoverWith { case _ ⇒ getClassFor(fqcn) }
+ classTry flatMap { c ⇒
+ Try {
+ val module = c.getDeclaredField("MODULE$")
+ module.setAccessible(true)
+ val t = implicitly[ClassTag[T]].runtimeClass
+ module.get(null) match {
+ case null ⇒ throw new NullPointerException
+ case x if !t.isInstance(x) ⇒ throw new ClassCastException(fqcn + " is not a subtype of " + t)
+ case x: T ⇒ x
+ }
+ } recover { case i: InvocationTargetException if i.getTargetException ne null ⇒ throw i.getTargetException }
+ }
+ }
+} \ No newline at end of file