1

I have this question of piping from python to java using communicate

import subprocess

str = ["haha", "hehe"]
p = subprocess.Popen("java -jar "hi.jar", stdin = subprocess.PIPE, stdout = subprocess.PIPE)
#p.communicate(str)

I would like to run communicate a list to my subprocess and obtain the output as a list

My question would be that how would java tackle this communication? As a list?

I am using this to handle it in java.

Scanner in = new Scanner(System.in)
//Not sure what to put here if i am using 
in.nextline()

I am trying to pipe a list to a java engine for processing and pipe the output as a list from java back to python

5
  • Maybe it would be easier to use a cmd/bash/etc. command as a glue layer? Commented Mar 18, 2015 at 1:17
  • @TigerhawkT3 the best idea i have is to write to a file and read from the file in java. But it will impact the performance greatly and hence not a viable solution. Commented Mar 18, 2015 at 1:23
  • Can you even run this in python? I don't think subprocess.Popen communicate function will take a list as an argument. Commented Mar 18, 2015 at 1:24
  • @Boris no i cannot. i am trying to say i wanna communicate a list. Commented Mar 18, 2015 at 1:26
  • You should be able to delimit by new line. I'll post an answer. Commented Mar 18, 2015 at 1:31

3 Answers 3

2

You will have to use a new line to delimit your strings.

import subprocess

l = "line 1\nline 2\nline 3"
p = subprocess.Popen(["java", "-jar", "hi.jar"], stdin = subprocess.PIPE)
p.communicate(l)

Your java code can look like this.

import java.util.Scanner;

public class ReadData
{
    public static void main(String[] args)
    {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            System.out.println(sc.nextLine() + " - line");
        }
    }
}

Create simple manifest file.

echo "Main-Class: ReadData" > manifest.txt

Compile java code with the javac ReadLine.java and pack the code into jar with the jar cvfm hi.jar manifest.txt *.class command.

Sign up to request clarification or add additional context in comments.

2 Comments

Wouldnt sc.hasNextLine() be better? I am using sc.nextline() instead of sc.next()
Absolutely. The difference between them is that the next will stop at space, and the nextLine will go all the way till it finds '\n'. Feel free to use whichever works for you case. I'll update answer.
1

There are a few options here:

  1. Use str() or repr() to convert the list to a string representation. then parse the string in Java.
  2. Split the list into separate lines and write each to the Java sub process, which puts them back together into a list.
  3. Use JSON. Send a JSON string of the list to Java and decode it with one of the many JSON libraries available.

I'd opt for the third option, JSON, because this gives more flexibility with the types of data structures that can be communicated. e.g. you might later find yourself wanting to transfer a Python dictionary. You might also later find that you want your Java application to send a reply, and JSON can be used here too.

Python to send the list as a JSON string:

import json
import subprocess

# send a Python list...
p = subprocess.Popen("java -jar "hi.jar", stdin=subprocess.PIPE, stdout=subprocess.PIPE)
o, e = p.communicate(json.dumps(["haha", "hehe"]))

>>> print o
handleInput():  got a JSONArray (list) containing 2 elements
haha
hehe

# send a Python dictionary...
p = subprocess.Popen("java -jar "hi.jar", stdin=subprocess.PIPE, stdout=subprocess.PIPE)
o, e = p.communicate(json.dumps({"hee": "haw", "blah": "blah"}))
>>> print o
handleInput():  got a JSONObject (map) containing 2 items
hee: haw
blah: blah

And sample Java code to receive and parse the JSON. It can handle basic lists and dictionaries. This uses the json-simple package for the parsing:

import java.util.Scanner;
import java.util.Iterator;

import org.json.simple.JSONObject;
import org.json.simple.JSONArray;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;


class JSONMessageHandler {
    void handleInput(JSONArray list)
    {
        System.out.println(
                "handleInput():  got a JSONArray (list) containing " +
                    list.size() + " elements");

        for (Object o : list)
            System.out.println(o);
    }

    void handleInput(JSONObject map)
    {
        System.out.println(
                "handleInput():  got a JSONObject (map) containing " +
                    map.size() + " items");

        for (Iterator it = map.keySet().iterator(); it.hasNext();)
        {
            Object key = it.next();
            System.out.println(key + ": " + map.get(key));
        }
    }
}


class Hi {
    public static void main(String[] args) throws ParseException {
        Scanner in = new Scanner(System.in);
        Object obj = new JSONParser().parse(in.nextLine());
        JSONMessageHandler msgHandler = new JSONMessageHandler();

        if (obj instanceof JSONArray)
            msgHandler.handleInput((JSONArray)obj);
        else if (obj instanceof JSONObject)
            msgHandler.handleInput((JSONObject)obj);
    }
}

Comments

1

Because you are unable to communicate a list with the subprocess communicate function, I would communicate each list member separately, then create an array (or java.util.List because java has no primitive list) using a for loop to add each member to the array.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.