aboutsummaryrefslogtreecommitdiff
path: root/kamon-core/src/main/scala/kamon/util/DynamicAccess.scala
diff options
context:
space:
mode:
Diffstat (limited to 'kamon-core/src/main/scala/kamon/util/DynamicAccess.scala')
-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