-
-
Save gzoller/9158363115a6bcd646f5 to your computer and use it in GitHub Desktop.
Problem creating object from reflected constructor in Scala
This file contains 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
package co.blocke.m2 | |
import scala.reflect.runtime.currentMirror | |
import scala.reflect.runtime.universe._ | |
case class PField( fieldName:String ) | |
case class PCaseClass( name:String, fields:List[PField], ctor:MethodMirror ) | |
// sample case classes | |
case class Simple(a:String, b:Int, c:Boolean) | |
class Inner(val underlying: String) extends AnyVal | |
case class Complex( hey:Inner, you:String ) | |
object Poof extends App { | |
private def poof( cc:PCaseClass, data:Map[String,Any] ) : Any = { | |
// Get constructor arguments in right order, we should. | |
val args = cc.fields.collect{ case f => data.get(f.fieldName).getOrElse(None) } | |
println(s"::: Poof : ${cc.name} with "+args.toList) | |
println( "--- Ctor : "+cc.ctor) | |
println( "--- Args : "+args.toList.map(_.getClass.getName)) | |
println( "--- Tried: "+scala.util.Try( cc.ctor.apply(args:_*) )) | |
cc.ctor.apply( args: _* ) | |
} | |
def getCtor[T]()(implicit tt:TypeTag[T]) : MethodMirror = { | |
val classSymbol = tt.tpe.typeSymbol.asClass | |
val ctor = classSymbol.primaryConstructor | |
val classMirror = currentMirror.reflectClass(classSymbol) | |
classMirror.reflectConstructor(ctor.asMethod) | |
} | |
//--------------------------- | |
val one = PCaseClass("co.blocke.m2.Simple", List(PField("a"),PField("b"),PField("c")), getCtor[Simple]()) | |
println(poof(one, Map("a"->"Wow","b"->5,"c"->true)).asInstanceOf[Simple]) | |
println("--------------------------------") | |
val two = PCaseClass("co.blocke.m2.Complex", List(PField("hey"),PField("you")), getCtor[Complex]()) | |
println(poof(two, Map("hey"->new Inner("ok"),"you"->"wow")).asInstanceOf[Complex]) | |
println(Complex(new Inner("ok"),"wow")) // comparison with direct value class instantiation | |
} | |
/* OUTPUT WHEN RUN | |
--- Ctor : constructor mirror for def <init>(a: String,b: scala.Int,c: scala.Boolean): co.blocke.m2.Simple (bound to null) | |
--- Args : List(java.lang.String, java.lang.Integer, java.lang.Boolean) | |
--- Tried: Success(Simple(Wow,5,true)) | |
Simple(Wow,5,true) | |
-------------------------------- | |
::: Poof : co.blocke.m2.Complex with List(co.blocke.m2.Inner@ddc, wow) | |
--- Ctor : constructor mirror for def <init>(hey: co.blocke.m2.Inner,you: String): co.blocke.m2.Complex (bound to null) | |
--- Args : List(co.blocke.m2.Inner, java.lang.String) | |
--- Tried: Success(Complex(co.blocke.m2.Inner@ddc,null)) | |
Complex(co.blocke.m2.Inner@ddc,null) | |
Complex(co.blocke.m2.Inner@ddc,wow) | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment