I have been playing around with JInterface and Elixir and I think I've got your problem figured out.
So you are trying to send a list of strings from an Elixir/Erlang node to a Java node, but you cannot get it to de-serialize properly.
Elixir has its own types (e.g., atoms
, tuples
, ..) and Java has its own types (e.g., Object
, String
, List<String>
,..). There needs to be a conversion from the one type to the other if they're supposed to talk to each other. In the end it's just a bunch of 1's and 0's that get sent over the wire anyway.
If an Erlang list is sent to Java, what arrives can always be interpreted as an OtpErlangObject
. It's up to you to then try and guess what the actual type is before we can even begin turning it into a Java value.
// We know that everything is at least an OtpErlangObject value!
OtpErlangObject o = mbox.receive();
But given that you know that it's in fact a list, we can turn it into an OtpErlangList
value.
// We know o is an Erlang list!
OtpErlangList erlList = (OtpErlangList) o;
The elements of this list however, are still unknown. So at this point its still a list of OtpErlangObject
s.
But, we know that it's a list of strings, so we can interpret the list of OtpErlangObject
s as list of OtpErlangString
s, and convert those to Java strings.
public static List<String> ErlangListToStringList(OtpErlangList estrs) {
OtpErlangObject[] erlObjs = estrs.elements();
List<String> strs = new LinkedList<String>();
for (OtpErlangObject erlO : erlObjs) {
strs.add(erlO.toString());
}
return strs;
}
Note that I used the term list here a lot, because it's in fact an Erlang list, in Java it's all represented as an array!
My entire code is listed below.
The way to run this is to paste it into a Java IDE, and start a REPL with the following parameters:
iex --name bob@127.0.0.1 --cookie "secret"
Java part:
import com.ericsson.otp.erlang.*;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
public class Main {
public static OtpErlangList StringListToErlangList(List<String> strs) {
OtpErlangObject[] elems = new OtpErlangObject[strs.size()];
int idx = 0;
for (String str : strs) {
elems[idx] = new OtpErlangString(str);
idx++;
}
return new OtpErlangList(elems);
}
public static List<String> ErlangListToStringList(OtpErlangList estrs) {
OtpErlangObject[] erlObjs = estrs.elements();
List<String> strs = new LinkedList<String>();
for (OtpErlangObject erlO : erlObjs) {
strs.add(erlO.toString());
}
return strs;
}
public static void main(String[] args) throws IOException, InterruptedException {
// Do some initial setup.
OtpNode node = new OtpNode("alice", "secret");
OtpMbox mbox = node.createMbox();
mbox.registerName("alice");
// Check that the remote node is actually online.
if (node.ping("bob@127.0.0.1", 2000)) {
System.out.println("remote is up");
} else {
System.out.println("remote is not up");
}
// Create the list of strings that needs to be sent to the other node.
List<String> strs = new LinkedList<String>();
strs.add("foo");
strs.add("bar");
OtpErlangList erlangStrs = StringListToErlangList(strs);
// Create a tuple so the other node can reply to use.
OtpErlangObject[] msg = new OtpErlangObject[2];
msg[0] = mbox.self();
msg[1] = erlangStrs;
OtpErlangTuple tuple = new OtpErlangTuple(msg);
// Send the tuple to the other node.
mbox.send("echo", "bob@127.0.0.1", tuple);
// Await the reply.
while (true) {
try {
System.out.println("Waiting for response!");
OtpErlangObject o = mbox.receive();
if (o instanceof OtpErlangList) {
OtpErlangList erlList = (OtpErlangList) o;
List<String> receivedStrings = ErlangListToStringList(erlList);
for (String s : receivedStrings) {
System.out.println(s);
}
}
if (o instanceof OtpErlangTuple) {
OtpErlangTuple m = (OtpErlangTuple) o;
OtpErlangPid from = (OtpErlangPid) (m.elementAt(0));
OtpErlangList value = (OtpErlangList) m.elementAt(1);
List<String> receivedStrings = ErlangListToStringList(value);
for (String s : receivedStrings) {
System.out.println(s);
}
}
} catch (OtpErlangExit otpErlangExit) {
otpErlangExit.printStackTrace();
} catch (OtpErlangDecodeException e) {
e.printStackTrace();
}
}
}
}