13
$\begingroup$

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

$\endgroup$
  • 3
    $\begingroup$ This is for fixing the uploader palette which was broken by API changes today. $\endgroup$ – Szabolcs Apr 5 '13 at 0:14
13
$\begingroup$

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] *)
$\endgroup$
  • $\begingroup$ +1 for the JLinkClassLoader`classFromName[] tip. $\endgroup$ – ford Jul 24 '13 at 20:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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