Using Java to wrap over C++

sparkFinder picture sparkFinder · Jul 28, 2010 · Viewed 19.5k times · Source

I have a project written in C++ and I'm looking to write a Java GUI as an interface to it. The choice of Java is fixed so I'd need to learn how to be able to call the C++ code from Java. Rewriting the C++ code is not an option. I'd like input on:

  1. What tools can I use to achieve this wrapping.
  2. How much of the C++ code would I have to necessarily modify, if any.
  3. Any other insights/follow up questions that you'd have.

Thanks.

Answer

Matt Crinklaw-Vogt picture Matt Crinklaw-Vogt · Jul 29, 2010

I recently worked on a project in which we had to do exactly the same thing. We had a data model written in C++ and needed to put a Java GUI on top. What we ended up doing was identifying the C++ classes that we needed to access from the GUI and used SWIG to generate plain old java classes which wrapped the C++ objects.

http://www.swig.org/

The Java classes generated by SWIG have identical interfaces to the C++ classes they are wrapping which means that communicating with the C++ objects, from Java, involves only working with Java objects.

Here is an example:

Given two C++ classes:

class SomeClass {
public:
  void foo(SomeOtherClass bar);
  SomeOtherClass baz();
}

class SomeOtherClass {
public:
  void do();
}

SWIG will generate two Java classes:

public class SomeClass {
  public void foo(SomeOtherClass bar);
  public SomeOtherClass baz();
}

public class SomeOtherClass {
  public void do();
}

Calling C++ objects, from Java, is just like writing regular Java:

SomeClass sc = new SomeClass();
SomeOtherClass soc = sc.baz();
sc.foo(soc);

Line 1: The Java wrapper of SomeClass is instantiated as well as a C++ object of type SomeClass.

Line 2: Calls to the sc instance of SomeClass are forwarded to the C++ instance of SomeClass. The return value of the C++ instance is passed to the Java wrapper and returned by the Java wrapper.

Line 3: SWIG handles converting from the Java wrapper types (or java primitive types) to the underlying C++ types.

SWIG will take care of converting to/from Java/C++ types during method invocations and all the JNI details are hidden away from view :)

The SWIG interface code needed to generate a Java wrapper for a C++ class can be as simple as:

interface.i: { #include "ClassDefinition.h" } %include "ClassDefinition.h"

SWIG is very powerful. Anything you need to do you can do either with the basic features, typemaps, javacode type maps, or directors.

SWIG also allows your C++ code to call your Java objects without any modification to your existing C++ code. This is a feature called "cross language polymorphism." cross language polymorphism essentially lets you create Java classes that subclass C++ classes. You can then pass instances of those Java classes as parameters to C++ method calls. Any invocations, from C++, on the passed in instance will be forwarded back to your Java object. I won't get into the details here, but it isn't terribly complicated once you get over the initial shock of the idea.