Dynamically instantiating case classes

791 views
Skip to first unread message

bg

unread,
Jan 7, 2015, 11:04:11 AM1/7/15
to lif...@googlegroups.com

This isn't a direct liftweb question - but I think the expertise in the community may be well placed to help me - as I think the framework does something along these lines (but properly :P)

I have a dream of "dynamically instantiating case classes" -- and providing some dummy data for the fields depending on each fields type (I'll create some rules for that later)

So far I have some code which works with case classes with StringLong or Int ... and am a bit stuck on if its possible to handle embedded case classes

So I can instantiate case class RequiredAPIResponse (stringValue: String, longValue: Long, intVlaue: Int)

but not Outer; where Outer is ...

case class Inner (deep: String)
case class Outer (in : Inner)

The code is

 def fill[T <: Object]()(implicit mf: ClassTag[T]) : T = {

      val declaredConstructors = mf.runtimeClass.getDeclaredConstructors
      if (declaredConstructors.length != 1)
      Logger.error(/*T.toString + */" has " + declaredConstructors.length + " constructors --- only 1 currently supported.")
      val constructor = declaredConstructors.headOption.get

      val m = constructor.getParameterTypes.map(p => {
          Logger.info("getName " + p.getName +" --- getCanonicalName " + p.getCanonicalName)
          Logger.info(p.getCanonicalName)

        p.getCanonicalName match {
          case "java.lang.String" => /*"Name"->*/ val s : java.lang.String = "DEFAULT STRING"
            s
          case "long" => /*"Name"-> */ val l : java.lang.Long = new java.lang.Long(99)
            l
          case "int" => /*"Name"->*/ val i : java.lang.Integer = new java.lang.Integer(99)
            i
          case _ => /*"Name"->*/

            So around here I am stuck!
        //THIS IS MADE UP :) But I want to get the "Type" and recursively call fill     
            //fill[p # Type] <- not real scala code

            //I can get it to work in a hard coded manner
            //fill[Inner]

        }
      })

I feel like the last answer on Scala: How to invoke method with type parameter and manifest without knowing the type at compile time? is a starting point for an answer. So instead of using T <: Object; fill should take ClassTag or a TypeTag?

This code started from - How can I transform a Map to a case class in Scala? - which mentions (as the Lift-Framework does) I do have the liftweb source code; but so far have been unsuccessful in untangling all its secrets.

Thanks, Brent

Antonio Salazar Cardozo

unread,
Jan 7, 2015, 11:32:35 PM1/7/15
to lif...@googlegroups.com
For nested objects I think lift-json uses the scalap library in conjunction with
the ScalaSig helper class. However, in Scala 2.10+ I think you can take the
Class[_] instance that you get from getParameterTypes and turn it into a ClassTag
by calling ClassTag(whatever), then pass that in explicitly to the manifest parameter:

constructor.getParameterTypes.map(p => {
          Logger.info("getName " + p.getName +" --- getCanonicalName " + p.getCanonicalName)
          Logger.info(p.getCanonicalName)


        p match {
          case _: Class[String] => /*"Name"->*/ val s : java.lang.String = "DEFAULT STRING"
            s
          case _: Class[long] => /*"Name"-> */ val l : java.lang.Long = new java.lang.Long(99)
            l
          case _: Class[int] => /*"Name"->*/ val i : java.lang.Integer = new java.lang.Integer(99)
            i
          case otherClass => /*"Name"->*/

            fill[_](whateverObject)(ClassTag(otherClass))

        //THIS IS MADE UP :) But I want to get the "Type" and recursively call fill     
            //fill[p # Type] <- not real scala code

            //I can get it to work in a hard coded manner
            //fill[Inner]

        }


Haven't tested this, no promises, but it may be a good path to follow. The scala-users mailing
list may be able to offer more help.
Thanks,
Antonio

bg

unread,
Jan 8, 2015, 2:25:38 AM1/8/15
to lif...@googlegroups.com
Great thanks for the pointers
Reply all
Reply to author
Forward
0 new messages