How to match classes of "boolean" types and "Boolean" types?
Consider the following code:
object U { def foo(s:String) = true }
val boolType = Class.forName("java.lang.Boolean")
val retType = U.getClass.getMethods.find(_.getName == "foo").get.getReturnType
boolType == retType // evaluates to false (*)
println (boolType) // prints "class java.lang.Boolean"
println (retType) // prints "boolean"
I would like retType
to match with boolType
in the line marked (*)
. How do I automatically equate classes of boxed and unboxed types?
[Edit:] I don't think this is the best solution, but one way is to make the comparison
retType.getCanonicalName == "boolean"
[Edit2:] The context: I am writing some code to automatically invoke a method based on a form name. The code should extract the return types etc from the method and return the appropriate answer. As an example, the fol开发者_运维技巧lowing snippet is used:
object someObject {}
val validTypes:Array[Class[_]] = Array(Class.forName("java.lang.String"),
someObject.getClass,
Class.forName("java.lang.Boolean"))
object U { def foo(s:String) = true } // can contain more methods
def getRetType(name:String) =
U.getClass.getMethods.find(_.getName == name).get.getReturnType
println ("Type is "+(if (validTypes.contains(getRetType("foo"))) "valid" else "invalid"))
When Java reflection wants to represent a primitive return type, it uses Class
instances that are not the same as the wrapper classes. So in Java, a boolean
return type is represented by a java.lang.Boolean.TYPE
(which in Java is also accessible as boolean.class
, and in Scala as classOf[Boolean]
).
So you want
scala> U.getClass.getMethods.find(_.getName == "foo").get.getReturnType ==
java.lang.Boolean.TYPE
res7: Boolean = true
Edit : I guess that comparing with classOf[Boolean]
would be a less JVM specific solution.
On the JVM, java.lang.Boolean
is the reference type. Your routine returns a scala Boolean
, which is java primitive boolean
. That one is not a class in the JVM. Its type is java.lang.Boolean.TYPE
, not classOf[Boolean]
(java.lang.Boolean.class
in java), which is what you get with Class.forName("java.lang.Boolean")
.
I think your only solution is to have an explicit mapping. Since you ask how to "(automatically) equate classes of boxed and unboxed types", I show an elegant way to define a comparison function.
First, instead of Class.forName
you can use classOf[Type]
, when the type is known at compile-time. Using this, you can define a canonicalizing mapping of unboxed to boxed types:
import java.{lang => jl}
val map = Map[Class[_], Class[_]](classOf[Boolean] -> classOf[jl.Boolean],
classOf[Int] -> classOf[jl.Integer]) //XXX add other entries
Then you can define a comparison function:
def cmp(lhs: Class[_], rhs: Class[_]) =
//Canonicalize before comparing
map.getOrElse(lhs, lhs) == map.getOrElse(rhs, rhs)
And test it:
scala> cmp(classOf[Boolean], classOf[jl.Boolean])
cmp(classOf[Boolean], classOf[jl.Boolean])
res13: Boolean = true
scala> cmp(classOf[Boolean], classOf[jl.Integer])
cmp(classOf[Boolean], classOf[jl.Integer])
res16: Boolean = false
To clarify the relation between classOf
and Boolean.TYPE
, here's a couple REPL interactions:
scala> classOf[java.lang.Boolean] == java.lang.Boolean.TYPE
res7: Boolean = false
scala> classOf[Boolean] == java.lang.Boolean.TYPE
res8: Boolean = true
精彩评论