Created
February 1, 2017 01:22
-
-
Save emesday/a3c747e1315429c48ba6c5ef25b5fd97 to your computer and use it in GitHub Desktop.
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
protected def typeToTypeTag[T](tpe: Type): TypeTag[T] = { | |
TypeTag(currentMirror, new TypeCreator { | |
override def apply[U <: Universe with Singleton](m: api.Mirror[U]): U#Type = { | |
tpe.asInstanceOf[U#Type] | |
} | |
}) | |
} | |
protected def typeToClassTag[T](tpe: Type): ClassTag[T] = typeTagToClassTag(typeToTypeTag(tpe)) | |
protected def typeTagToClassTag[T](typeTag: TypeTag[T]): ClassTag[T] = ClassTag[T](typeTag.mirror.runtimeClass(typeTag.tpe)) | |
protected def toClass[T](tpe: Type): Class[T] = typeToClassTag(tpe).runtimeClass.asInstanceOf[Class[T]] | |
protected def toClass[T](tt: TypeTag[T]): Class[T] = typeTagToClassTag(tt).runtimeClass.asInstanceOf[Class[T]] | |
protected def toJavaListClass[T](clazz: Class[T]): Class[util.List[T]] = { | |
classOf[java.util.List[T]] | |
} | |
protected def paramType[T]()(implicit tt: TypeTag[T]): Type = { | |
val a = typeOf[T] match { case TypeRef(_, _, args) => args } | |
a.head | |
} | |
protected def getProperty[T](key: String, tpe: Class[T])(implicit tt: TypeTag[T]): Option[_] = { | |
val clazz = if (tpe.isAssignableFrom(classOf[Option[Any]])) { | |
toClass(paramType()(tt)) | |
} else if (tpe.isAssignableFrom(classOf[Seq[_]])) { | |
toJavaListClass(toClass(paramType()(tt))): Class[_] | |
} else { | |
tpe | |
} | |
var v = Try(underlying.head.getProperty(key, clazz)).toOption | |
var i = 1 | |
while (v.isEmpty && i < underlying.length) { | |
v = Try(underlying(i).getProperty(key, clazz)).toOption | |
i += 1 | |
} | |
v | |
} | |
protected def newCaseClass[A](prefix: String)(implicit t: ClassTag[A]): A = { | |
val module = currentMirror.classSymbol(t.runtimeClass).companion.asModule | |
val instanceMirror = currentMirror.reflect(currentMirror.reflectModule(module).instance) | |
val typeSignature = instanceMirror.symbol.typeSignature | |
val method = typeSignature.member(TermName("apply")).asMethod | |
val args = method.paramLists.flatten.zipWithIndex.map { case (sym, i) => | |
val key = s"$prefix.${sym.name.toString.replace("$u002E", ".")}" | |
logger.debug(s"key: $key, sym: ${sym.typeSignature}") | |
sym.typeSignature match { | |
case t if t <:< typeOf[Product] && !(t <:< typeOf[Option[_]]) => | |
// case class | |
newCaseClass(key)(typeToClassTag(t)) | |
case t if t <:< typeOf[Option[Product]]=> | |
scala.util.Try(newCaseClass(key)(typeToClassTag(paramType()(typeToTypeTag(t)))): Any).toOption | |
case t if t <:< typeOf[Seq[Product]] => | |
// Seq[case class] | |
throw new NotImplementedError | |
case t if t <:< typeOf[Option[Seq[Product]]] => | |
// Option[Seq[case class]] | |
throw new NotImplementedError | |
case t => | |
getProperty(key, toClass(sym.typeSignature))(typeToTypeTag(sym.typeSignature)) match { | |
case Some(v) => | |
val c = v match { | |
case v: java.util.Collection[_] if t <:< typeOf[Option[_]] => Some(v.toArray.toSeq) | |
case v: java.util.Collection[_] => v.toArray.toSeq | |
case v if t <:< typeOf[Option[_]] => Some(v) | |
case v => v | |
} | |
logger.debug(s"set value from config: $c") | |
c | |
case None => | |
val defaultArgument = typeSignature.member(TermName(s"apply$$default$$${i + 1}")) | |
if (defaultArgument != NoSymbol) { | |
// set to defaultArgument | |
val v = instanceMirror.reflectMethod(defaultArgument.asMethod)() | |
logger.debug(s"set value from default value: $v") | |
v | |
} else { | |
// no defaultArgument | |
sym.typeSignature match { | |
case t if t <:< typeOf[Option[_]] => | |
logger.debug("set None") | |
None | |
case _ => throw new NoSuchElementException(s"Not Found: $key") | |
} | |
} | |
} | |
} | |
} | |
instanceMirror.reflectMethod(method)(args: _*).asInstanceOf[A] | |
} | |
def bind[T: ClassTag](prefix: String): T = { | |
newCaseClass[T](prefix.replace("-", ".")) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment