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$ Commented 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$ Commented 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$ Commented 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$ Commented Jul 31, 2015 at 4:54

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.