Reputation: 874
I have a DSL and some runtime code. The problem is I got somewhere at runtime:
val clazz: Class[_ <: java.io.Serializable] = classOf[java.lang.String]
val value: java.io.Serializable = "abc"
and I have a class
class MyWrapper[T <: java.io.Serializable](val data: T)(implicit m: Manifest[T]) {
override def toString = m.runtimeClass
}
val wrapper = new MyWrapper(value)
The problem is I need to return java.lang.String
from a call of toString
. But I got java.io.Serializable
. Unfortunately I am neither able to create fixed pattern matching for each java.io.Serializable
subtype (this would be crazy) nor to create MyWrapper
explicit with new MyWrapper[String](value)
. I don't know the type of value
, maybe it is a subtype of Serializable
.
Is there some way to pass type/manifest value at runtime if I know that value type is equal to variable clazz
?
Update (solution from Régis Jean-Gilles don't work). REPL test:
val clazz: Class[_ <: java.io.Serializable] = classOf[java.lang.String]
val value: java.io.Serializable = "abc"
class MyWrapper[T <: java.io.Serializable](val data: T)(implicit m: Manifest[T]) {
override def toString = m.runtimeClass.getName
}
val wrapper = new MyWrapper(value)
//val wrapper = new MyWrapper(value)(ClassManifest.fromClass(clazz).asInstanceOf[ClassTypeManifest[java.io.Serializable]])
//val wrapper = new MyWrapper(value)(ClassManifest.fromClass(clazz))
System.err.println(wrapper.toString)
I got an error, if I tried to pass manifest explicit:
scala> :load test.scala
Loading test.scala...
clazz: Class[_ <: java.io.Serializable] = class java.lang.String
value: java.io.Serializable = abc
defined class MyWrapper
<console>:10: error: type mismatch;
found : scala.reflect.ClassManifest[_$1] where type _$1 <: java.io.Serializable
(which expands to) scala.reflect.ClassTag[_$1]
required: Manifest[java.io.Serializable]
val wrapper = new MyWrapper(value)(ClassManifest.fromClass(clazz))
^
<console>:8: error: not found: value wrapper
System.err.println(wrapper.toString)
Also I am unable to cast manifest explicit.
There is more strange error when I try to compile my application -
[error] found : scala.reflect.ClassManifest[(some other)_0(in method setProperty)]
[error] (which expands to) scala.reflect.ClassTag[(some other)_0(in method setProperty)]
[error] required: Manifest[_0(in method setProperty)]
[error] new Value.Static(default, Context.virtual(element))(ClassManifest.fromClass(elementProperty.typeClass)))
IMHO Régis Jean-Gilles very very close to solution. How to make it work with Scala 2.10?
Upvotes: 2
Views: 1254
Reputation: 32729
If I understand correctly, you are using manifests to work around type erasure but at a specific point all you have is a Class[_]
so you need to convert it back to a manifest. Correct?
If so, you can use ClassManifest.fromClass
, and then explicitly pass it as the implicit value m
.
val wrapper = new MyWrapper(value)(Manifest.classType(clazz))
You should probably abstract it away:
object MyWrapper {
def fromRuntimeType[T <: java.io.Serializable]( value: T ): MyWrapper[T] = {
new MyWrapper(value)(Manifest.classType(value.getClass))
}
}
Keep in mind though that because you only have a Class
instance in the first place, you are at the mercy of type erasure again. This means that if the class (that you need to get a manifest for) is generic, you won't have any type parameter information in the manifest returned by ClassManifest.fromClass
.
Upvotes: 2
Reputation: 12852
Wouldn't
override def toString = data.getClass.getName
already work for you? That yields java.lang.String
.
Upvotes: 0