vendredi 15 avril 2016

Passing type in Scala as an argument

I want to pass a type to a function in Scala.

Problem in detail

First iteration

I have the following Java classes (coming from an external source):

public class MyComplexType {
    public String name;
    public int number;
}

and

public class MyGeneric<T> {
    public String myName;
    public T myValue;
}

In this example I want MyComplexType to be the the actual type of MyGeneric; in the real problem there are several possibilities.

I want to deserialize a JSON string using a Scala code as follows:

import org.codehaus.jackson.map.ObjectMapper

object GenericExample {
  def main(args: Array[String]) {
    val jsonString = "{\"myName\":\"myNumber\",\"myValue\":{\"name\":\"fifteen\",\"number\":\"15\"}}"
    val objectMapper = new ObjectMapper()
    val myGeneric: MyGeneric[MyComplexType] = objectMapper.readValue(jsonString, classOf[MyGeneric[MyComplexType]])
    val myComplexType: MyComplexType = myGeneric.myValue
  }
}

it compiles fine but runtime error occurs:

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to MyComplexType
        at GenericExample$.main(GenericExample.scala:9)

Second iteration

Working solution to the problem:

val jsonString = "{\"myName\":\"myNumber\",\"myValue\":{\"name\":\"fifteen\",\"number\":\"15\"}}"
val objectMapper = new ObjectMapper()
val myGeneric: MyGeneric[MyComplexType] = objectMapper.readValue(jsonString, classOf[MyGeneric[MyComplexType]]) 
myGeneric.myValue = objectMapper.readValue(objectMapper.readTree(jsonString).get("myValue").toString, classOf[MyComplexType])
val myComplexType: MyComplexType = myGeneric.myValue

Not nice but works. (If anybody knows how to make it better, that would also welcome.)

Third iteration

The lines in the solution of second iteration occur in the real problem several times, therefore I want to create a function. The altering variables are the JSON formatted string and the MyComplexType.

I want something like this:

def main(args: Array[String]) {
  val jsonString = "{\"myName\":\"myNumber\",\"myValue\":{\"name\":\"fifteen\",\"number\":\"15\"}}"
  val myGeneric = extractMyGeneric[MyComplexType](jsonString)
  val myComplexType: MyComplexType = myGeneric.myValue
}

private def extractMyGeneric[T](jsonString: String) = {
  val objectMapper = new ObjectMapper()
  val myGeneric = objectMapper.readValue(jsonString, classOf[MyGeneric[T]])    
  myGeneric.myValue = objectMapper.readValue(objectMapper.readTree(jsonString).get("myValue").toString, classOf[T])
  myGeneric
}

This does not work (compiler error). I've already played around with various combinations of Class, ClassTag, classOf but none of them helped. There were compiler and runtime errors as well. Do you know how to pass and how to use such a type in Scala? Thank you!





Aucun commentaire:

Enregistrer un commentaire