views:

321

answers:

3

I am writing a Java application that uses a C++ library through a JNI interface. The C++ library creates objects of type Foo, which are duly passed up through JNI to Java.

Suppose the library has an output function

    void Foo::print(std::ostream &os)

and I have a Java OutputStream out. How can I invoke Foo::print from Java so that the output appears on out? Is there any way to coerce the OutputStream to a std::ostream in the JNI layer? Can I capture the output in a buffer the JNI layer and then copy it into out?

A: 

How can I invoke Foo::print from Java so that the output appears on out?

Conceptually speaking, the way to get Foo::print(...) to write to an existing Java OutputStream instance is to write a C++ std::ostream implementation that actually does a callback into Java to do output.

That sounds possible, but I wouldn't want to write / maintain the code. At runtime, you'll have calls going from Java -> C++ -> Java, and there are lots of opportunities for making mistakes that will randomly crash your JVM.

Is there any way to coerce the OutputStream to a std::ostream in the JNI layer?

AFAIK no.

Can I capture the output in a buffer the JNI layer and then copy it into out?

Do you mean something roughly like this?

    MyJNIThing m = ...
    int myOstream = m.createMemoryBackedOStream(...); // native method
    ...
    m.someMethodWrapper(... myOStream); // native method
    ...
    byte[] data = m.getCapturedData(myOStream); // native method
    out.write(data);

You can probably make something like that work ... on a good day with a following wind.

But I think you should really be aiming to eliminate the C++ code rather than trying to do increasingly complicated things across JNI. IMO, JNI should only be used as a last resort, and not a short cut to avoid recoding stuff in Java.

Stephen C
Reimplementing the library in Java is not an option (it is large, mature, and performance intensive).
Chris Conway
Perhaps you should not be trying to call it from Java then. My point is that you are likely to create a lot of pain for yourself and people who have to maintain your code.
Stephen C
While I agree JNI code is tricky saying one should outright avoid it is not fair. There is definitely a Place for JNI, specifically with large legacy projects like the op mentioned and in my case 3rd party APIs that you must use to get the job done. This is a very valid question, one I'm looking for an answer to as well.
Cliff
@Cliff - well good luck to you too. Notice that NOBODY has offered one yet.
Stephen C
Good luck has been rewarded to me as I am now offering one example myself! See my coming answer below.
Cliff
A: 

I've posted a writeup on my blog detailing my recent experience with this very same problem. In general, you want to avoid trying to connect an input or output stream to a client in any language as it implies threads. You can incrementally deliver the data using callbacks.

Cliff
+1  A: 

I would implement a C++ ostream that buffers writes (Up to some set size) before flushing those writes to a java OutputStream via JNI.

On the java side, you can either use a regular OutputStream instance, or you can implement queueing of the buffer blocks (essentially byte[]) to avoid any possible locking contention between threads. The real output stream is used only by a task on another thread that pulls blocks from the queue and writes them to the OutpuStream. I can't say if this is necessary or not at this level of detail - you may well find writing directly to the output stream from JNI works.

I don't share the other posters concerns with JNI, and don't see any problem with using JNI for this. Sure, your maintainers will have to know their stuff, but that's about it, and the complexity of the Java/C++ layer can be managed with documentation, examples and test cases. In the past, I've implemented a Java<>COM bridge with quite a chatty interface - no problem with performance, threading or maintainance.

Given a totally free choice, there'd be no JNI, but for me, it has saved the day by making possible the tight integration of otherwise incompatible systems.

mdma