开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜