1

I had to write my own JDK dynamic proxy to provide the ability of dynamic interface implementation. Since I work with akka it has to be written in Scala. But I faced with some pretty strange behavior differs from Java:

object Main extends App {
    println(classOf[Message].getDeclaredMethod("msg")
                            .invoke(Message("Test"), null)) 
                          //throws IllegalArgumentException
}

case class Message(message: String){
  def msg() = message
}

StackTrace:

Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at Main$.delayedEndpoint$Main$1(Main.scala:2)
    at Main$delayedInit$body.apply(Main.scala:1)
    at scala.Function0$class.apply$mcV$sp(Function0.scala:34)
    at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
    at scala.App$$anonfun$main$1.apply(App.scala:76)
    at scala.App$$anonfun$main$1.apply(App.scala:76)
    at scala.collection.immutable.List.foreach(List.scala:381)
    at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35)
    at scala.App$class.main(App.scala:76)
    at Main$.main(Main.scala:1)
    at Main.main(Main.scala)

DEMO

But I in Java it works fine:

public static void main (String[] args) throws java.lang.Exception
{
    System.out.println(Message.class.getDeclaredMethod("msg")
              .invoke(new Message(), null)); //prints Message
}

public static class Message{
    public String msg(){
        return "Message";
    }
}

DEMO

Why does Scala throw exception? And how to fix it?

4
  • 4
    I bet Scala wraps the null argument differently, into its own arguments instead of to mean no arguments. Just remove it from the invocation. Commented Aug 26, 2016 at 14:30
  • 1
    @SotiriosDelimanolis is right, without the null yields what you expect Commented Aug 26, 2016 at 14:36
  • @SotiriosDelimanolis Very interesting, but don't you know the exact Scala magic about null? Commented Aug 26, 2016 at 14:54
  • Akka has Java interface, you are not obliged to write in Scala. Commented Dec 6, 2016 at 13:05

1 Answer 1

3

Hopefully I can demonstrate what is going on:

class TheClass { 
  def theMethod:Unit = { println("It's me the method"); } 
}

scala> classOf[TheClass].getDeclaredMethod("theMethod").invoke(new TheClass, null)
java.lang.IllegalArgumentException: wrong number of arguments
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

scala> classOf[TheClass].getDeclaredMethod("theMethod").invoke(new TheClass)
It's me the method
res1: Object = null

As expected, but now have a look at this:

scala> classOf[TheClass]
      .getDeclaredMethod("theMethod").invoke(new TheClass, Array.empty)
java.lang.IllegalArgumentException: wrong number of arguments

Versus this:

scala> classOf[TheClass]
       .getDeclaredMethod("theMethod").invoke(new TheClass, Array.empty : _*)
It's me the method
res4: Object = null

Notice the difference between the invokes: .invoke(new TheClass, Array.empty) vs .invoke(new TheClass, Array.empty : _*). What happens is that invokes second argument is a varargs, which should be turned into a array under the hood, when it's given a plain Array.empty or null scalac is replacing them with Array(Array.empty) and Array(null). When the argument is not provided it's actually Array.empty and when we use : _* it just telling the compiler that the argument we are proving is the varargs itself.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.