Boost logo

Boost :

Subject: [boost] [rfc] Java Binding library
From: Felipe Magno de Almeida (felipe.m.almeida_at_[hidden])
Date: 2012-10-21 17:24:35


Hello,

I'm developing a Java Binding library and would like feedback so that
it may in the future become a boost library.
I know quite well the luabind library and from reading the
documentation and tested a few toy
examples the boost.python library. Though they are very high quality
libraries, they have one thing in common
that doesn't apply to Java: dynamic typing (Lua actually just uses
tables). So just using a closed set of types
for function prototypes is not enough to convey the information
necessary to create the function descriptors
for JNI binding, and constructing classes in Java with all
Java/Lang/Object as parameters is not at all very
useful.

So, I thought that allowing the user to actually create classes in C++
that represents these objects
in Java would make for these differentiations in function signature,
and actually bind Java classes to
C++. And for a few simple examples these worked well. For example (the
syntax is not at all fixed yet):

struct PrintStream_class : jvb::extends<PrintStream_class,
FilterOutputStream_class>
{
  PrintStream_class(jvb::environment e)
    : base_type(e, "java/io/PrintStream")
  {}
};

struct PrintStream : FilterOutputStream
{
  typedef PrintStream_class class_type;

  typedef jvb::method_overload
  <void(bool)
   , void(jvb::char_)
   , void(jvb::array<jvb::char_>)
   , void(jvb::double_)
   , void(jvb::float_)
   , void(jvb::int_)
   , void(jvb::long_)
   , void(jvb::object)
   , void(jvb::string)
> print_overload;

  PrintStream(jvb::environment e, jobject obj)
    : FilterOutputStream(e, obj)
    , println(e, obj, "println")
    , print(e, obj, "print")
    , checkError(e, obj, "checkError")
  {}

  print_overload println;
  print_overload print;
  jvb::method<bool()> checkError;
};

which could be used with the definition of System, et al, this way:

int main()
{
  jvb::jvm jvm;
  jvb::environment env = jvm.environment();

  System_class system(env);
  system.out.println(env, "Hello World");
}

Which is at https://github.com/felipealmeida/javabind/blob/master/demo/inheritance/inheritance.cpp

The Hello World example is actually this:

int main()
{
  jvb::jvm jvm;
  jvb::environment env = jvm.environment();

  jvb::jcl::java::lang::System::class_type System(env);

  System.out.println(env, "Hello World");
}

This seemed fine, but it actually complicated a bit things when I
start to expose classes
in C++ to Java. This is the example that I'm trying to make work right now:

struct hello_world
{
  hello_world()
  {
    std::cout << "hello_world::hello_world" << std::endl;
  }

  void print()
  {
    std::cout << "hello_world::print Hello World" << std::endl;
  }
};

int main()
{
  jvb::jvm jvm;
  jvb::environment e = jvm.environment();

  using namespace jvb::bind_placeholders;

  jvb::Class c = jvb::bind_class<hello_world>
    (e, "HelloWorld"
     , (
        method(public_, "print", &hello_world::print)
       ));

  jvb::constructors<void()> constructor(e, c);
  jvb::Object object = jvb::new_<jvb::Object>(e, constructor);
  jvb::method<void()> print(e, object.raw(), "print");
  print(e);
}

The problem here is that hello_world actually represents a 'peer
class' in the JNI jargon.
This peer class is instantiated by a native function and set into a
member of the Java
class as a long and this is then requested by other native calls (or
just passed as
parameter to the native function, by a helper java function) which
then uses these
peer classes as the native state of the Java class. But, this peer
class doesn't represent
its own class in Java, so, if I'm to use this Java class as parameter
to some other
function I can't really use this class. And for matters to be worse,
jobject references,
used for jvb::object, can be of various types and the most used
jobject reference can't
really be saved, because it would not be valid later, or if I make it
valid (global reference)
the it would pin the object and leak.

Has this problem been dealt with in another language binding? Is it
really important not to
lose static information? Does another technique would fit better

Any input would be greatly appreciated.

If you have any examples of how the library should look like
syntactically for some use-cases,
that would be helpful too.

I'm completely rewriting the library right now, so the source code can
be a bit confusing right
now, also, most things are still hardcoded for the evolution and to
test how certain solutions
might work together, as a proof-of-concept.

The library's source code is available at
https://github.com/felipealmeida/javabind.

Thanks for the attention,

-- 
Felipe Magno de Almeida

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk