5
$\begingroup$

I'm trying to reproduce a Java code in Mathematica using JLink, I'm making calls to an API in a JAR file.

For one of the function call an empty list of a given type is needed but I don't know the syntax to create it with JLink.

The call in Java has the following syntax java.util.Collections.<String>emptyList() where I've put String as type for the element of the list for the example.

Is it possible to create a generic list with JLink ?

Generic lists are talked about here for example http://tutorials.jenkov.com/java-collections/list.html

Thank you

$\endgroup$

1 Answer 1

5
$\begingroup$

Java's implementation of generics uses erased types. Consequently, there is not actually any runtime implementation difference between, say, a List<Integer> and a List<String>. The virtual machine representation of both types is actually just List<Object>. From within Mathematica, we need not (and cannot) explicitly express any generic type parameters. We must work with generic types as if all type parameters were Object, remaining silent as to generic types. So, for example:

Needs["JLink`"]
InstallJava[];
LoadJavaClass["java.util.Collections"];

JavaBlock@Module[{list}
, list = Collections`emptyList[]
; list@size[]
]
(* 0 *)

JavaBlock@Module[{list}
, list = JavaNew["java.util.ArrayList"]
; list@add[MakeJavaObject@#]& /@ Range[5]
; Collections`reverse[list]
; JavaObjectToExpression[list]
]
(* {5,4,3,2,1} *)

In the second example, take note that we had to explicitly convert the integers into Java objects using MakeJavaObject. If we had not, then JLink would have looked for a non-existent method with the signature ArrayList#add(int) instead of the valid method ArrayList#add(Object).

JLink, unlike a Java compiler, does not offer any "compile time" checking of generic type arguments. So the burden is passed to us to make sure that we are creating generic parameters that are type-compatible with whatever API we are calling. If an API calls for a List<String>, and we pass a List<Integer>, the API will simply behave badly at runtime. If we are lucky, it will fail outright with a ClassCastException. If we are unlucky, it could just malfunction quietly and subtly. Take care to match the required types.

$\endgroup$
4
  • $\begingroup$ Thank you for the clarification. $\endgroup$
    – faysou
    Nov 3, 2014 at 15:55
  • $\begingroup$ So if an API wants type parameters passed to a constructor/factory method in order to function correctly, there is no way to access that functionality via JLink? In my particular case I am trying to create caches on a remote cluster using methods like .createCache<KeyClass, ValueClass>(). The method reads annotations in those classes to populate certain querying features; if it is called without the type parameters those features are unavailable. I'm just out of luck, right? $\endgroup$
    – mfvonh
    Jul 31, 2015 at 1:58
  • $\begingroup$ @mfvonh The generic type arguments are inaccessible to such APIs -- even in Java. In the absence of source preprocessing or other out-of-band information, those APIs will require us to pass class objects as explicit method arguments somewhere along the line. JLink allows us to pass class arguments provided we recover the native class objects using JLinkClassLoader. For example, see (22730). [...continued...] $\endgroup$
    – WReach
    Jul 31, 2015 at 4:53
  • $\begingroup$ @mfvonh If you are referring to implementing a Java interface in JLink, and the API requires the implementations to carry annotations then, yes, we are out of luck. JLink has no current support for implementing annotations. $\endgroup$
    – WReach
    Jul 31, 2015 at 4:54

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.