13

When using J/Link, how can we create an array out of objects belonging to different classes but having the same base class?

Here's an example:

partSource = 
  JLink`JavaNew[
   "org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource", "mmagraphics.png", 
   JLink`MakeJavaObject["abcdefg"]@toCharArray[]];
part1 = JLink`JavaNew[
   "org.apache.commons.httpclient.methods.multipart.FilePart", 
   "filename", partSource];
part2 = JLink`JavaNew[
   "org.apache.commons.httpclient.methods.multipart.StringPart", 
   "someting", "1234"];

MakeJavaObject[{part1, part2}]

Java::excptn: A Java exception occurred: java.lang.IllegalArgumentException: array element type mismatch at java.lang.reflect.Array.set(Native Method).

I need to create a Part [] out of {part1, part2} so that I can pass it to the constructor of org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263

1 Answers1

13

We can start by creating the parts using the same code as the question:

partSource = 
  JavaNew[
    "org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource",
    "mmagraphics.png", 
    MakeJavaObject["abcdefg"]@toCharArray[]];

part1 =
  JavaNew[
    "org.apache.commons.httpclient.methods.multipart.FilePart", 
    "filename", partSource];

part2 =
  JavaNew[
    "org.apache.commons.httpclient.methods.multipart.StringPart", 
    "someting", "1234"];

We want to create an array whose components are of the type Part. We will need a reference to that class. A normal JLink reference is not good enough -- we need the Java object that represents the class. We use the JLink class loader to get this reference:

LoadJavaClass["com.wolfram.jlink.JLinkClassLoader"];

partClass =
  JLinkClassLoader`classFromName[
    "org.apache.commons.httpclient.methods.multipart.Part"];

We can then use the Array class to create an array of the correct type and fill in its elements:

LoadJavaClass["java.lang.reflect.Array"];

parts =
  ReturnAsJavaObject @ Array`newInstance[partClass, 2];
Array`set[parts, 0, part1]
Array`set[parts, 1, part2]

Note carefully the use of ReturnAsJavaObject. Without it, the carefully constructed array would be immediately converted back to a Mathematica list.

We now have everything we need to construct the required MultipartRequestEntity:

post =
  JavaNew[
    "org.apache.commons.httpclient.methods.PostMethod",
    "http://somewhere/over/the/rainbow"];

multipart = JavaNew[
  "org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity",
  parts,  
  post@getParams[]]

(* JavaObject[org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity] *)
WReach
  • 68,832
  • 4
  • 164
  • 269