1

I cannot figure out whether I am using piped streams improperly or whether my problem is elsewhere in the issue below.

I have an object (called 'adi') that I marshal into a file as shown below:

  final PipedInputStream pipedInputStream = new PipedInputStream();
  OutputStream pipedOutputStream = null;
  pipedOutputStream = new PipedOutputStream(pipedInputStream);
  log.info("marshalling away");
  final OutputStream outputStream = new FileOutputStream(new File(
          "target/test.xml"));
  m.marshal(adi, outputStream);
  outputStream.flush();
  outputStream.close();
  pipedOutputStream.write("test".getBytes());
  // m.marshal(adi, pipedOutputStream);
  pipedOutputStream.flush();
  pipedOutputStream.close();
  log.info("marshalling done");
  return pipedInputStream;
  • That code generates a file target/test.xml with the content that I expect (marshalled object), validating that the marshalling into the outputStream works properly.
  • The code also generates a pipedInputStream. If I iterate through the bytes pulled from that stream and print them, it displays "test", validating the fact that my input/output pipe stream is properly setup and working.

Yet, when I uncomment

  //m.marshal(adi, pipedOutputStream);  

the code hangs forever (never displaying "marshalling done") while I would expect the code to return an input stream containing "test" followed by my marshalled object.

What am I missing?

Thanks

double07
  • 2,565
  • 2
  • 22
  • 22

1 Answers1

3

I think you're trying to use it incorrectly...

From the API (http://docs.oracle.com/javase/6/docs/api/java/io/PipedInputStream.html):

Typically, data is read from a PipedInputStream object by one thread and data is written to the corresponding PipedOutputStream by some other thread. Attempting to use both objects from a single thread is not recommended, as it may deadlock the thread.

What you want to do is this:

  log.info("marshalling away");
  final OutputStream fileOutputStream = new FileOutputStream(new File(
          "target/test.xml"));
  m.marshal(adi, fileOutputStream);
  fileOutputStream.flush();
  fileOutputStream.close();
  final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
  outputStream.write("test".getBytes());
  m.marshal(adi, outputStream);
  outputStream.flush();
  final InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
  outputStream.close();
  log.info("marshalling done");
  return inputStream;

See here for more examples of how to turn an output stream into input stream: http://ostermiller.org/convert_java_outputstream_inputstream.html

There is a way using a temporary thread that you can do something similar to your original solution and piped streams.

MattJenko
  • 1,208
  • 8
  • 11
  • What you say makes sense. So let me ask a more general question: if my contract is to return an InputStream which will contain my marshalled object, what should be my approach? Am I stuck marshalling my object into a StringWriter or a FileWriter, and then turn the resulting string or file into an inputStream? Is there something more efficient resource wise? – double07 Dec 01 '11 at 17:56
  • Sorry, have updated my answer to include an example of what to do, along with a link to other possibilities (one that is similar to your original solution but using a temporary thread to do the PipedOutputStream part. – MattJenko Dec 01 '11 at 18:14
  • Thanks, I did pretty much the same as what you wrote above except that I went through a FileInputStream and FileOutputStream to reduce memory requirements. You nailed my issue in your first comment: I was expecting this code to execute in a separate thread (producing the data as they were being consumed) without setting up any multithreading environment. Thanks for the help. – double07 Dec 01 '11 at 18:18
  • As I said, there is another alternative and that is to do almost exactly what you were doing, but do the 'm.marshal(adi, outputStream)' part inside a thread. See the last link I provided, under 'Use Pipes' – MattJenko Dec 01 '11 at 18:33