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$
1
  • 3
    $\begingroup$ This is for fixing the uploader palette which was broken by API changes today. $\endgroup$
    – Szabolcs
    Apr 5, 2013 at 0:14

1 Answer 1

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

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.