Accessing static methods of parameterized Java classes from Scala - java

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())
}

Related

What is the difference between a constructor and a builder when using generics?

While programming in Java, I encountered the following problem.
when use Constructor: The following code works fine.
public class Generics<T> {
private T data;
public static <T> Generics<T> of(T data) {
return new Generics<>(data);
}
public Generics(T data) {
this.data = data;
}
}
when use builder: An error occurs saying that the Object type is provided as follows.
I used a builder provided by Project Lombok.
Why doesn't the builder generic in the code above work?
Evidently Lombok generates a static generic builder() method. You can specify the generic type of a generic static method using <T> before the method name, as in:
return Generics.<T>builder()
.data(data)
.build();
If you don't specify the generic type when you call builder(), you get a raw type, at which point generic type inference no longer works.
You need to explicitly add the generics: return Generics.<T>builder() - add that <T> and all will be well.
Explanation
Java is aggressively typed: Every expression and just about every part of an expression has an actual type; java does not allow things to remain in limbo until later; there's no such thing as 'an intermediate - eh, we'll see where it goes'.
That means Generics.builder(), as an expression, needs to be typed by the system. The builder class needs that <T> just the same (it's a Generics.GenericsBuilder<X> - where Builder is a static inner class of Generics, and is defined as public static class GenericsBuilder<X>.
Java cannot just jump to the conclusion that you intend for X and T to be the same type.
Looking ahead, it can figure out that X should be T 'automatically', without your involvement: It can either check the .data(data) invocation, given that the data method is defined in the builder as:
public GenericsBuilder<X> data(X data)
thus, whatever type data (the variable)might be (it'sThere, given that it's the parameter defined asT data`), and therefore, java can conclude that the X should be T.
Otherwise, java can look even further ahead, to build(), and notice that this returns X, and is being returned by a method whose return type is defined as T, thus also giving java the opportunity to say: Ah, X == T, right.
But that is not how java works. In large part because even figuring out what the .data method might mean is rather hard to do when the X of that builder you just made (the X in the declaration public static <X> Generics.GenericsBuilder<X> builder()) must be left in some sort of unknown limbo state for a while as the parser carries on with trying to figure out what the rest means. Given that java allows method overloading (2 different methods with the same name and the same number of params, but different param types, which could contain generics to boot) - it'd be a combinatorial explosion and means you can write java code that takes literally years to parse.
Hence, java does not work that way, it must determine what X is supposed to be solely from the expression Generics.builder(), and it clearly cant.
The solution is to just write it explicitly, using this somewhat exotic syntax: Generics.<T>builder().

how to explain generics used in ImmutableList.builder().build() in guava?

I just saw this kind of code ImmutableList<String> list= ImmutableList.<String>builder().build();
which really confused me. How to understand the diamond after ImmutableList.?
Most parameterized types in java show up on a type. This looks like so:
interface List<T> {
void add(T elem);
}
So, any List type is parameterized, and as generics is really just a mechanism to link things, what it links is that a List<String> has an add method that takes String objects, and a get(int) method that returns a String, etc.
But, methods themselves may also want this linking behaviour. For example, let's say I want to make a method that takes 2 arguments of the same type, and returns the first non-null one. Here too I want to link things: The types of the 2 argument, and the return type? All the same thing, caller's choice as to what it might be.
Java supports this: Methods can ALSO have generics:
public <T> T firstNonNull(T a, T b) {
return a == null ? b : a;
}
is valid java, and you can call it:
String a = firstNonNull("hello", "world!");
Compiles without requiring a cast.
Java will infer generics if it can; it does that in my previous example (the two arguments are both strings; java infers you meant T to be String there). But you can, if you want, be explicit about it. This is where this funky syntax comes in:
Number a = ClassContainingFNN.<Number>firstNonNull(null, null);
You need the dot to use this syntax, hence why I had to make the call a little longer. With the ImmutableList builder method, java can't (easily) infer what type you wanted, as the call to builder() itself doesn't let the compiler know that you're attempting to build a list of, say, strings. That's why forcing it by explicitly telling java what you want the type param to be is useful, thus, why the usual way to call this builder is:
ImmutableList.<String>builder().add(aString).add(anotherString).build();
Java will always try to infer something if you don't explicitly pick something, but it would just infer Object here. Unless you wanted a list of objects, you need the 'forcibly pick a type' option.
See java support jls-15.12 for supporting TypeArguments after entering Type.
MethodInvocation:
MethodName ( [ArgumentList] )
TypeName . [TypeArguments] Identifier ( [ArgumentList] )
The builder is generic method
public static <E> Builder<E> builder()
And because it's static you entered before method name the type using diamond operator
In case of new instance it'll be as you expected:
new ImmutableList.Builder<Color>()

Java Reflection in Scala

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.

Calling private Java methods in Scala

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.

Scala Tuple type inference in Java

This is probably a very noobish question, but I was playing a bit with Scala/Java interaction, and was wondering how well did Tuples play along.
Now, I know that the (Type1, Type2) syntax is merely syntactic sugar for Tuple2<Type1, Type2>, and so, when calling a Scala method that returns a Tuple2 in a plain Java class, I was expecting to get a return type of Tuple2<Type1, Type2>
For clarity, my Scala code:
def testTuple:(Int,Int) = (0,1)
Java code:
Tuple2<Object,Object> objectObjectTuple2 = Test.testTuple();
It seems the compiler expects this to be of parameterized types <Object,Object>, instead of, in my case, <Integer,Integer> (this is what I was expecting, at least).
Is my thinking deeply flawed and is there a perfectly reasonable explanation for this?
OR
Is there a problem in my Scala code, and there's a way of being more... explicit, in the cases that I know will provide an API for Java code?
OR
Is this simply a limitation?
Int is Scala's integer type, which is a value class, so it gets special treatment. It is different from java.lang.Integer. You can specify java.lang.Integer specifically if that's what you need.
[dlee#dlee-mac scala]$ cat SomeClass.scala
class SomeClass {
def testIntTuple: (Int, Int) = (0, 1)
def testIntegerTuple: (java.lang.Integer, java.lang.Integer) = (0, 1)
}
[dlee#dlee-mac scala]$ javap SomeClass
Compiled from "SomeClass.scala"
public class SomeClass implements scala.ScalaObject {
public scala.Tuple2<java.lang.Object, java.lang.Object> testIntTuple();
public scala.Tuple2<java.lang.Integer, java.lang.Integer> testIntegerTuple();
public SomeClass();
}

Categories

Resources