Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rJava generics type

Tags:

java

r

rjava

I have been playing with rJava package, but since it seems that rJava is not aware of Java generic types, I have difficulties creating java object with generic type parameters. If I have a java class like:

public class A<T> {
    private B<T> b;
    public A(B<T> b) {
        this.b = b;
    }
}

I would like to create an A object from R session using .jnew() by passing a B object already created (with instantiated type parameter), but rJava always gives error:

java.lang.NoSuchMethodError: <init>

Is there any work around for this?

like image 506
user2166795 Avatar asked Mar 13 '13 18:03

user2166795


1 Answers

There are a lot of moving parts in this question. Digging through the documentation for the various parts, I think that you need to do this on the line that broke:

gesinstance = .jnew("edu/cmu/tetrad/search/Ges", .jcast(dataset, "edu/cmu/tetrad/data/DataSet"))

The key difference being the call to .jcast on the second argument. (I don't have R installed, so I could not test this - If it doesn't work, I will update my answer based on any feedback you can provide on new error messages.)

So then the question is "why that?" The answer seems to be:

  1. On the Java side, DataReader.parseTabularData returns an object with type DataSet as you noted, but DataSet is an interface not a class. That necessarily means that the actual object returned is of some class that implements the DataSet interface.
  2. For reasons that aren't immediately clear to me, the rJava package does not really handle polymorphism well. It requires that you call methods with an "exact" signature match to the objects that you are passing. In this case, you will need to "up-cast" from whatever specific class you got to the interface DataSet. See the documentation for .jnew (https://www.rforge.net/doc/packages/rJava/html/jnew.html), especially for the arguments that they denote by "...". This refers you to the corresponding part of the documentation for .jcall (https://www.rforge.net/doc/packages/rJava/html/jcall.html), when then explains the requirement to call .jcast (https://www.rforge.net/doc/packages/rJava/html/jcast.html) with some examples.

The error that you got java.lang.NoSuchMethodError: <init> was telling you that the JVM could not find the constructor that you called. This was mysterious looking in the example that you posted in the comments. (It might be good to edit your question, by the way, and include that information up there for posterity.) The code certainly looks right, and, knowing Java, I intuitively expected the interface to respect the polymorphism of the Java. Given that (for whatever reason), the interface to R does "exact" type matching without considering inheritance, it's clear that it will not find a constructor due to reason #1 above.

Finally, I didn't actually encounter any Java classes using generics in my limited exploration of Tetrad. As it turns out, that was a complete red herring though. Should it be an issue in the future, you'll probably want to check out "Type Erasure" (https://docs.oracle.com/javase/tutorial/java/generics/erasure.html). If you were interfacing between Java and C, C++, Fortran, any language that Java considers "native," then you'd deal with the generics in the native code by dealing in the type-erased forms. The rJava interface may be different though, since this seems to fall into the same general type of structure that tripped you up on your current problem. (Maybe worthy of its own bounty later!)

like image 170
Brick Avatar answered Oct 12 '22 16:10

Brick