I am trying to get a simple java reflection program working in Scala, and seem to be missing something ...
scala> val cl = new URLClassLoader(Array(new File("Hi.jar").toURI.toURL), getClass.getClassLoader)
cl: java.net.URLClassLoader = java.net.URLClassLoader#3c7b137a
scala> val c = cl.loadClass("Hi")
c: Class[_] = class Hi
scala> val m = c.getMethod("run")
m: java.lang.reflect.Method = public void Hi.run()
scala> m.invoke()
<console>:21: error: not enough arguments for method invoke: (x$1: Any, x$2: Object*)Object.
Unspecified value parameters x$1, x$2.
m.invoke()
^
What am I missing, as the prior line has indicated -
public void Hi.run()
What exactly is it expecting for the two arguments?
Scala is telling you exactly what your problem is: invoke needs 1+ parameters!
See the java doc:
invoke(Object obj, Object... args)
Invokes the underlying method represented by this Method object, on the specified object with the specified parameters.
So, you have to provide at least one argument - a reference to the object (or class) you want to call that method on! As Hi.run() seems to be static, you would want to use your c as only argument to your call.
The following arguments would be the actual parameters that your "reflected" method expects. In your case, no further arguments.
Long story short: you better keep the excellent tutorials from Oracle on reflection close to your scala console while experimenting. If you try to learn "reflection" by trial&error; I guarantee you: a lot of frustrating trials with many strange errors. Really: the reflection API is not very forgiving when you don't know what you are doing; even the slightest mistakes can lead to very unexpected results.
There is nothing specific to Scala there. Method.invoke requires the at least one argument being the instance on which it's applied (or null for a static method).
In Scala, you can use structural typing for such simple case.
Related
This following declaration is legal in Kotlin.
fun foo(): String = "foo_1"
fun <T> foo(): T = "foo_2" as T
As bytecode we are getting:
public final static foo()Ljava/lang/String;
// signature <T:Ljava/lang/Object;>()TT;
// declaration: T foo<T>()
public final static foo()Ljava/lang/Object;
It's also possible to call both of these methods from Kotlin.
The problem comes when I'm trying to call any of them from Java:
ClassKt.foo()
Ambiguous call. Both methods match ...
How to avoid such a problem? How to deal with such methods? What if 3-rd party kt library has same issue?
The example above is a synthetic one.
Why does it work with Kotlin to begin with... In Java having two methods like:
private static String test() {
return "";
}
private static <T> T test() {
return null;
}
would result in a compile time error. And for java devs this is sort of obvious, these methods would have the same type erasure. But this is rule imposed by javac, not by the JVM where this code runs. So javac does not treat two methods as having only a different return type as overloads. Well, kotlin is a different language and since it runs on the JVM (that expects valid byte-code) it allows treating methods with only the return type being different as overloads. I am yet to look at the byte code and understand how that happens; it also seems that this will work only for generic code, so may be type erasure is slightly different in case of kotlin.
Now, things should be obvious why calling such a method from java fails. Kotlin offers a neat solution for this: #JvmName("someDistinctName"). I am not entirely sure how this works under the hood either... yet, though I assume this will create a bridge method.
EDIT
#JvmName will rename the method at the byte-code level.
You can use #JvmName to differentiate the code when it's called from java:
#JvmName("fooString")
fun foo(): String = "foo_1"
fun <T> foo(): T = "foo_2" as T
This will allow calling the String method in Java with ClassKt.fooString(), which resolves the clash.
An easy solution would be writing a helper method in Kotlin and just calling that.
Another way using only Java would be getting a MethodHandle for both methods and using them:
MethodHandle MH_fooString = lookup().findStatic(ClassKt.class, "foo", methodType(String.class));
MethodHandle MH_fooT = lookup().findStatic(ClassKt.class, "foo", methodType(Object.class));
String foo = (String) MH_fooString.invokeExact();
It's not nearly as simple and requires handling exceptions though.
In Scala, I am doing some Java interop. I am creating a value of class Sample.Individual and I am calling a static Java method like Sample.Individual.newBuilder(). I am using a few classes that all have this same static method (eg: Sample.Position and Sample.Feature). I want to make a function that parameterizes over them, so something like:
def p[T](s: String): T = {
val pb = T.newBuilder() // this returns a value of type T.Builder
... do stuff with pb ...
pb.build() // this returns a value of type T
}
but this tells me "not found: value T"
What is the right way to parameterize the type Sample.Individual that lets me also call static methods contained in it from Scala?
I'd strongly recommend you don't go forward with this idea. Even if you find a way to do it, it's not idiomatic Scala. It's remotely possible you shave off a few lines of code, but you loose in readability and performance; bad trade-off.
The problem you're having is that you're giving your p function a type parameter T, and then invoking the newBuilder method on that type T. You can't do that, because Scala knows nothing about your type T.
Instead, first learn a little more about those Java types. Do all the potentially constructed classes extend a common type? If not, you're out of luck (you're technically not out of luck if you choose to pimp the library you're using, but please don't :P).
Otherwise, just import those types (including the generic one). Put the generic type as the type of your p function and match on the string, then just instantiate your type. Strings can be whatever, so you probably want to return an Option[GenericClass] rather than a GenericClass.
e.g.
import xxx.GenericClassBuilder
import xxx.GenericClass
import xxx.ClassA
import xxx.ClassB
def p(s: String): Option[GenericClass] = {
val maybePb: Option[GenericClassBuilder] = s match {
case "ClassA" => Some(ClassA.newBuilder())
case "ClassB" => Some(ClassB.newBuilder())
case _ => None
}
maybePb.foreach { pb => ... do side-effecty stuff with pb ...}
maybePb.map(_.build())
}
I regularly use the Scala REPL for rapid Java iteration and testing, but sometimes I want to trigger some private behavior of a class, and have to recompile the code in order to make the method visible. I'd like to be able to call private Java methods directly in the REPL, without needing to make code changes.
What I've got so far:
// Calls private Java methods
// We currently define an overload for every n-argument method
// there's probably a way to do this in one method?
def callPrivate(obj: AnyRef, methodName: String) = {
val method = obj.getClass().getDeclaredMethod(methodName)
val returnType = method.getReturnType
method.setAccessible(true)
println("Call .asInstanceOf[%s] to cast" format method.getReturnType.getName)
method.getReturnType.cast(method.invoke(obj))
}
def callPrivate(obj: AnyRef, methodName: String, arg: AnyRef) = {
val method = obj.getClass().getDeclaredMethod(methodName, arg.getClass())
method.setAccessible(true)
method.invoke(obj, arg)
}
Which can be used like:
scala> callPrivate(myObj, "privateMethod", arg).asInstanceOf[ReturnedClass]
But this requires defining a near duplicate method for every n-argument method type (and requires an external cast, but I suspect that's unavoidable). Is there any way to refactor this so that one function can handle any number of arguments?
Note: I'm using Scala 2.9.1, so I'm looking for solutions using Java Reflection. Answers using Scala Reflection are welcome, but don't address my problem directly.
DISCLAIMER: There has been a while since the last time I programmed in Scala and I don't have any kind of Scala environment around to test what I am showing you. So it might have small syntax errors here and there, bear with me. Hope the rest is useful
In theory you could provide our callPrivate method with an extra variable argument that specifies the method parameters:
def callPrivate(obj: AnyRef, methodName: String, parameters:AnyRef*) = {
val parameterTypes = parameters.map(_.getClass())
val method = obj.getClass.getDeclaredMethod(methodName, parameterTypes:_*)
method.setAccessible(true)
method.invoke(obj, parameters:_*)
}
There is a flaw however. This won't work if you have a method somewhere with a signature like this:
public X someMethod(A parameter);
and A is inherited (or implemented) by class B. If you try to invoke your Scala method this way callPrivate(someObject, "someMethod", new B()) it won't work mostly because the getDeclaredMethod lookup will search for someMethod(B) instead of someMethod(A) - even when new B() is of type A too!
So that's a naive implementation. You could potentially get all the valid types of all the method parameters and perform the getDeclaredMethodlookup with all the combinations for them, however there is one more caveat in that direction: You might bump with overloaded methods that accept different combinations of the same set of parameters and you will not know which one to call (i.e. you may have someMethod(A,B) and someMethod(B,A) and you won't be able to know which one should be invoked)
One way avoid that is to force the caller to provide you with tuples instead of raw instances, each tuple has the parameter value and the parameter type to be used. So it is up to the caller to specify which method he want to invoke.
def callPrivateTyped(obj: AnyRef, methodName: String, parameters:(AnyRef,Class[_])*) = {
val parameterValues = parameters.map(_._1)
val parameterTypes = parameters.map(_._2)
val method = obj.getClass.getDeclaredMethod(methodName, parameterTypes:_*)
method.setAccessible(true)
println("Call .asInstanceOf[%s] to cast" format method.getReturnType.getName)
method.invoke(obj, parameterValues:_*)
}
// for convenience
def callPrivate(obj: AnyRef, methodName: String, parameters:AnyRef*) = {
callPrivateTyped(obj, methodName, parameters.map(c => (c, c.getClass)):_*)
}
That should do the trick.
Also, one more thing: Keep in mind that the way you are using getDeclaredMethod will only return methods (with any scope) that are implemented in obj.getClass(), meaning that it won't return any inherited method. I don't know if that is by design, if not you will need to add a recursive lookup over the superclasses of your obj.
Is there a way to statically reference a method for reflection in Java. Here's some example code to give you an idea of what I am attempting:
public void myFunc(int x) { ... }
public void other() {
Method m1 = getClass().getMethod("myFunc"); // dynamic
Method m2 = this.myFunc; // static
Method m3 = MyClass.myFunc; // static (alternate)
}
I recognize that the above syntax does not work, but I was wondering if there is some sort of syntax similar to this that actually does work. I want a way to use reflection without worrying about the inherent dangers of referencing a method by a string.
Is there a way to do this, or is it just a pipe-dream?
Method references explains
this method to compare the birth dates of two Person instances already exists as Person.compareByAge. You can invoke this method instead in the body of the lambda expression:
Arrays.sort(rosterAsArray,
(a, b) -> Person.compareByAge(a, b)
);
Because this lambda expression invokes an existing method, you can use a > method reference instead of a lambda expression:
Arrays.sort(rosterAsArray, Person::compareByAge);
and it goes on to explain the various kinds of method references:
There are four kinds of method references:
Reference to a static method ContainingClass::staticMethodName
Reference to an instance method
of a particular object containingObject::instanceMethodName
Reference to an instance method ContainingType::methodName
of an arbitrary object of a
particular type
Reference to a constructor ClassName::new
HISTORICAL NOTE (Written before Java 8 was finalized)
I think the Java closures proposal has something like this. Stephen Colebourne says:
Stefan and I are pleased to announce the release of v0.4 of the First-class Methods: Java-style closures proposal.
Changes
Since v0.3, we have tried to incorporate some of the feedback received on the various forums. The main changes are as follows:
1) Constructor and Field literals. It is now possible to create type-safe, compile-time changed instances of java.lang.reflect.Constructor and Field using FCM syntax:
// method literal:
Method m = Integer#valueOf(int);
// constructor literal:
Constructor<Integer> c = Integer#(int);
// field literal:
Field f = Integer#MAX_VALUE;
but I don't think this syntax is available in any shipping JVM. Closures themselves are definitely not in Java 7. You might see it in Java 8.
The Java closures site has a pointer to "Method references" which is a bit more up-to-date though it doesn't look like they've changed the syntax much.
JSR-335 is what you're looking for. Hopefully it will be available in JDK 8.
I'm converting someone else's java code to scala (for the curious, it's the example here) and I hit a compiler error on the following (simplified somewhat):
var out = new Formatter(new StringBuilder(), Locale.US)
out.format("%s-%d ", someObject, someInteger);
And here's the error message I get:
[error] (java.util.Locale,java.lang.String,<repeated...>
[java.lang.Object])java.util.Formatter <and>
[error] (java.lang.String,<repeated...>[java.lang.Object])java.util.Formatter
[error] cannot be applied to (java.lang.String, java.lang.Object, Int)
...
[error] one error found
This works if I change the second line to:
out.format("%s-%d ", someObject, someInteger.asInstanceOf[Object]);
Can someone explain why this is?
Does this mean that it's ok in java to pass integers where object arguments are expected but not in scala?
The other answers all add something, but I'm not sure they explain what the problem is.
It all comes down to Int being a class in Scala while int is a primitive in Java. So, in Java, when you write that a method expects an Object, and you pass an int, Java will auto-box it in a java.lang.Integer.
Now, Java's java.lang.Object equivalent in Scala is AnyRef, but Int is not a subclass of AnyRef. There's a proper type for that: Any. An Any can contain both things which are subclasses of java.lang.Object as well as the stuff that are primitives in Java. If you say a method expects Any and pass an Int, then it will be auto-boxed, but not for AnyRef.
So, whenever you interface with Java and a method expects you to pass boxed primitives, you'll have to force the boxing yourself. You can create a method expecting Any in Scala, and then cast it to AnyRef and call the Java equivalent, to make things easier if you are going to call that method a lot.
The class hierarchy isn't the same in java and scala. java.lang.Object is at the root of the hierarchy in java. In scala, the Any type is at the root. So, anything can be passed to a function which takes a parameter of type Any. However, only subtypes of java.lang.Object can be passed to a function which takes a parameter of type java.lang.Object.
To make matters worse, there's two types of integers. There's scala's Int type, and java.lang.Integer. The former is what you usually get when you set something to a number literal in scala. The latter is what you get with new Integer(3) or 3.asInstanceOf[Integer]. It turns out that the scala Int does not inherit from java.lang.Object, but java.lang.Integer does inherit. As a result you can't pass a scala Int as a parameter expecting a java.lang.Object. That's why this doesn't work in scala.
Java's story is a little weird. In the past it used to be that java ints couldn't be passed where an object was expected; you needed to explicitly convert them into java.lang.Integer. However, a somewhat recent change (version 5) does this for you automatically. This is called autoboxing or unboxing, depending on which way the conversion is going. So that's why it works in java.
You don't specify how someInteger is defined, but I assume you are trying to do something like this:
val someObject: Object = "this"
val someInteger = 3
var out = new Formatter(new StringBuilder(), Locale.US)
out.format("%s-%d ", someObject, someInteger);
The problem is that when you say someInteger = 3 in Scala, then the variable is Scala's Int and not Java's int, and Java's Formatter doesn't know what to do with it.
If you change your declaration to use an integer type that Java can understand, then it works just fine. For example:
import java.lang.Integer
val someInteger = new Integer(3)
As for why the ugly asInstanceOf version works? A quick check on the REPL will show you what's happening:
scala> 3.asInstanceOf[java.lang.Object].getClass
res0: java.lang.Class[_ <: java.lang.Object] = class java.lang.Integer
So when you call .asInstanceOf[java.lang.Object] on an Int, Scala gives you back a java.lang.Integer.
But really, you should just rewrite the code in a more Scala-ish way. Andrew McCallum would be happier if you did.
As dhg has said, the scala compiler treats Scala int types as different to Java int types. You could try importing the JavaConversions implicits and see if that helps. I don't quite understand the exact difference (I would have thought it'd treat them the same).
Alternatively you can use the Scala formatting tools:
val someObject: Object = "this"
val someInteger = 3
val out = "%s-%d ".format(someObject, someInteger)