Преобразование двоичного ответа из приложения JInterface Java обратно в список строк в Elixir - PullRequest
2 голосов
/ 31 января 2020

У меня небольшое приложение java, и я использовал JInterface, чтобы по существу представить его как процесс OTP в моем приложении elixir. Я могу позвонить и получить ответ успешно.

Моя проблема в том, что ответ, который я получаю обратно в эликсире, - это двоичный файл, но я не могу понять, как преобразовать двоичный файл в список строк. Ответ:

Код для моего узла OTP в Java с использованием JInterface приведен ниже:

public void performAction(Object requestData, OtpMbox mbox, OtpErlangPid lastPid){
    List<String> sentences = paragraphSplitter.splitParagraphIntoSentences((String) requestData, Locale.JAPAN);
    mbox.send(lastPid, new OtpErlangBinary(getOtpStrings(sentences)));
    System.out.println("OK");
}

private List<OtpErlangString> getOtpStrings(List<String> sentences) {
    List<OtpErlangString> erlangStrings = new ArrayList<>();
    for(int i = 0; i < sentences.size(); i++){
        erlangStrings.add(new OtpErlangString(sentences.get(i)));
    }
    return erlangStrings;
}

Необходимо обернуть ответ в OtpErlangBinary, и я согласовал строки для OTPErlangString. Я также пытался без преобразования строк в OTPErlangString.

На стороне эликсира я могу получить бинарный ответ и IO.inspect.

Кто-нибудь знает, как использовать JInterface для десериализации результатов правильно, когда это что-то, кроме одной строки? Или, может быть, если я допустил какую-то ошибку, как построить правильный тип ответа, чтобы я мог правильно десериализовать его?

Любая помощь будет очень признательна, поскольку я пытался выяснить это целую вечность. Заранее спасибо.

1 Ответ

1 голос
/ 06 февраля 2020

Я играл с JInterface и Elixir, и, думаю, я понял твою проблему.

Итак, вы пытаетесь отправить список строк из узла Elixir / Erlang в узел Java, но вы не можете заставить его десериализоваться должным образом.

Эликсир имеет свои собственные типы (например, atoms, tuples, ..), а Java имеет свои собственные типы (например, Object, String, List<String>, .. ). Должно быть преобразование из одного типа в другой, если они должны общаться друг с другом. В конце концов это всего лишь набор из 1 и 0, которые все равно отправляются по проводам.

Если список Erlang отправляется на Java, то, что прибывает, всегда можно интерпретировать как OtpErlangObject. Затем вы должны попытаться угадать, что это за тип, прежде чем мы сможем даже превратить его в значение Java.

// We know that everything is at least an OtpErlangObject value!
OtpErlangObject o = mbox.receive();

Но учитывая, что вы знаете, что это на самом деле список, мы можем превратить его в значение OtpErlangList.

// We know o is an Erlang list!
OtpErlangList erlList = (OtpErlangList) o;

Элементы этого списка все еще неизвестны. Так что на данный момент это все еще список OtpErlangObject с.

Но мы знаем, что это список строк, поэтому мы можем интерпретировать список OtpErlangObject s как список OtpErlangString s и преобразовать их в Java строки.

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;
}

Обратите внимание, что здесь я часто использовал термин список, потому что на самом деле это список Эрланга, в Java он все представлен в виде массива!

Весь мой код указан ниже. Чтобы выполнить это, вставьте его в Java IDE и запустите REPL со следующими параметрами:

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();
            }
        }
    }
}
...