将来自 JInterface Java 应用程序的二进制响应转换回 Elixir 中的字符串列表

Posted

技术标签:

【中文标题】将来自 JInterface Java 应用程序的二进制响应转换回 Elixir 中的字符串列表【英文标题】:Converting binary response from JInterface Java app back into list of strings in Elixir 【发布时间】:2020-05-17 11:58:28 【问题描述】:

我有一个小型 Java 应用程序,我使用 JInterface 将其作为 OTP 进程在我的 elixir 应用程序中公开。我可以调用它并成功得到响应。

我的问题是我在 elixir 中得到的响应是二进制的,但我不知道如何将二进制转换为响应的字符串列表。

使用 JInterface 的 Java OTP 节点代码如下:

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】:

我一直在玩 JInterface 和 Elixir,我想我已经解决了你的问题。

因此,您尝试将字符串列表从 Elixir/Erlang 节点发送到 Java 节点,但无法正确反序列化。

Elixir 有自己的类型(例如,atomstuples、..),而 Java 也有自己的类型(例如,ObjectStringList&lt;String&gt;、..)。如果他们应该相互交谈,则需要从一种类型转换为另一种类型。最后,无论如何,它只是一堆 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;

然而,这个列表的元素仍然未知。所以此时它仍然是OtpErlangObjects 的列表。

但是,我们知道它是一个字符串列表,所以我们可以将OtpErlangObjects 的列表解释为OtpErlangStrings 的列表,并将它们转换为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;

请注意,我在这里经常使用术语列表,因为它实际上是一个 Erlang 列表,在 Java 中它都表示为一个数组!

下面列出了我的整个代码。 运行它的方法是将其粘贴到 Java IDE 中,并使用以下参数启动 REPL:

iex --name bob@127.0.0.1 --cookie "secret"

Java部分:

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

【讨论】:

感谢您的回答。 :)

以上是关于将来自 JInterface Java 应用程序的二进制响应转换回 Elixir 中的字符串列表的主要内容,如果未能解决你的问题,请参考以下文章

Elixir - 在监督下启动 Java JInterface OTP 节点

通过 Jinterface 调用 gen_server?

erlang和java通信

通过 REST 访问 Erlang 业务层

应该使用啥代码页/字符集将来自 MVS 系统的数据解释为 Java 环境?

需要帮助来存储来自Java Web应用程序的许多文档