KajMagnus
KajMagnus

Reputation: 11666

How do I get Scala's Option class so I can pass it to getDeclaredMethod()

I'm trying to get the classOf[the-abstract-class-Option], but instead I always get the classOf[the-Option-*object*]. How can I get the class of the abstract class instead?

Both Option.getClass and classOf[Option[_]] gives me class scala.Option$.

Edit: I needn't have asked this; all of a sudden, classOf[Option[_]] works fine, weird. /Edit

Background:

I'm trying to invoke via reflection a method that takes an Option[String] parameter.
It signature look like so: ...(..., anySectionId: Option[String], ...)...
Before I can invoke the method, I look it up via getDeclaredMethod. But to do that, I need a list of parameter types, which I construct by calling _.getClass on each argument I'm going to give to the method. But _.getClass returns classOf[None] or classOf[Some] for Option instances, which makes getDeclaredMethod fail, because (?) the signature is based on Option not Some/None.

Here's the code:

val clazz: Class[_] = Play.current.classloader.loadClass(className)

val paramTypes = arguments.map(_ match {
  case None => Option.getClass  // gives me the object, not the abstract class
  case _: Some[_] => classOf[Option[_]]  // this also gives me the object  :-(
  case x => x.getClass  // results in None or Some for Option instances
})

val m: jl.reflect.Method = clazz.getDeclaredMethod("apply", paramTypes: _*)

and the last line above fails for a method with any Option parameter (otherwise everything works fine).

Upvotes: 0

Views: 593

Answers (2)

som-snytt
som-snytt

Reputation: 39577

The best way is use Scala reflection.

The next best way is not to make work for yourself by trying to match the param types.

Using getClass fails for subtypes:

scala> class Foo
defined class Foo

scala> class Bar extends Foo
defined class Bar

scala> class Baz { def baz(f: Foo) = 1 }
defined class Baz

scala> val b = new Baz
b: Baz = Baz@d33eaa9

scala> val p = new Bar
p: Bar = Bar@406c5ca2

scala> classOf[Baz].getDeclaredMethod("baz", p.getClass)
java.lang.NoSuchMethodException: Baz.baz(Bar)

It's easier just to match on the name:

scala> classOf[Baz].getMethods.find(_.getName == "baz") map (_.invoke(b,p)) getOrElse -1
res5: Any = 1

or filter on the number of params for poor man's overloading resolution, then maybe filter on all args having conforming types.

The notation for accidentally getting the object is in fact:

scala> classOf[Option$]
res8: Class[Option$] = class scala.Option$

Upvotes: 1

KajMagnus
KajMagnus

Reputation: 11666

Answer: classOf[Option[_]]

Weird! Suddenly classOf[Option[_]] works. I feel sure I tested once or twice before I submitted the question :-( Perhaps the IDE didn't have time to save the file before I recompiled, weird.

I don't know if I should delete the question. Or perhaps I should leave it as is, in case classOf[Option[_]] isn't obvious to everyone.

Upvotes: 1

Related Questions