Over a million developers have joined DZone.
Platinum Partner

How to Access C++ from Java

· Java Zone

The Java Zone is brought to you in partnership with ZeroTurnaround. Discover how you can skip the build and redeploy process by using JRebel by ZeroTurnaround.

JNIEasy is a development Java library focused on JNI access to C/C++ native methods. Here Jose, its creator, tells you all about it via an example scenario. And he asks: "What native libraries do you know of that could be interesting to access from Java?" -- Geertjan Wielenga, JavaLobby Zone Leader

JNIEasy goes the extra mile, using transparent Java-native synchronization. Any Java POJO can represent a C++ object, including instance methods and fields. A field modified in Java modifies the native field too and vice versa. Optionally, Java methods can be called from native C/C++ code, using pointers to functions with no JNI code. This “transparent native programming” is a translation to the Java-native world of techniques used in transparent persistence such as JPA or JDO.

Below follows a brief tutorial on how you can mix your C/C++ code with Java. The two worlds can be mixed in a way so transparent that it is difficult to distinguish when our task is executed in C++ and when in Java, although making the distinction is of course possible, should we want to do so.

The following Java class:

    public class MyCPPClassOnDLL


protected int virtualTable; // the C++ class has a virtual method

protected double value;

public MyCPPClassOnDLL() { // mandatory (is not native)


public MyCPPClassOnDLL(int a, int b) {

throw new RuntimeException("Not enhanced");


public native static void destroy(MyCPPClassOnDLL obj);

public native static long addStatic(int a,int b);

public double getValue() {

return value;


public native double sub(int a,int b);

public native static void varargsEx(byte[] buffer,Object[] args);

...is designed as a wrapper for this C++ class:
#include "JNIEasy.h"

// MyCPPClassOnDLL.h
double m_value;

MyCPPClassOnDLL(int a,int b);
virtual ~MyCPPClassOnDLL();

static MyCPPClassOnDLL* __stdcall create(int a,int b);

static void __stdcall destroy(MyCPPClassOnDLL* obj);

static __int64 __stdcall addStatic(int a,int b);

double __stdcall getValue();

virtual double __stdcall sub(int a,int b);

static void __cdecl varargsEx(char* buffer,...);


#include "MyCPPClassOnDLL.h"
#include <stdio.h>
#include <stdarg.h>

MyCPPClassOnDLL::MyCPPClassOnDLL(int a,int b)
m_value = a + b;


MyCPPClassOnDLL* __stdcall MyCPPClassOnDLL::create(int a,int b)
return new MyCPPClassOnDLL(a , b); // may be an inherited class

void __stdcall MyCPPClassOnDLL::destroy(MyCPPClassOnDLL* obj)
delete obj;

__int64 __stdcall MyCPPClassOnDLL::addStatic(int a,int b)
return (__int64)a + (__int64)b;

double __stdcall MyCPPClassOnDLL::getValue()
return m_value;

double __stdcall MyCPPClassOnDLL::sub(int a,int b)
m_value = m_value - (a + b);
return m_value;

void __cdecl MyCPPClassOnDLL::varargsEx(char* buffer,...)
va_list marker;
va_start( marker, buffer );
const char* name = va_arg( marker, const char*);
int age = va_arg( marker, int);
int brothers = va_arg( marker, int);
va_end( marker );

sprintf(buffer,"%s is %d years old and has %d brothers",name,age,brothers);

...where DLLEXPORT is __declspec(dllexport) on Windows (unixes by default export all methods) and __int64 is a macro defined as long long in unixes. These macros are defined by JNIEasy.h

Consider the C++ class is linked in a dynamic library called MyLibrary.dll on Windows, libMyLibrary.so on Linux/Solaris ,and libMyLibrary.dylib on Mac OS X. These names are the typical conventions of these operating systems and JNIEasy tries to follow these conventions by default. However, they are not mandatory. In JNIEasy, any custom dynamic library name can be used.

The Java class must be declared as "native" with JNIEasy. It can be "enhanced" to bind this class to the C++. To do this, we need an XML descriptor. The XML declares our Java class as JNIEasy-native and explains how to bind the desired methods to native methods:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Archive MyCPPClassOnDLL.jnieasy.enh.xml -->
<jniEasyEnhancer version="1.1">

<package name="examples.manual">
<class name="MyCPPClassOnDLL" type="class" libraryPath="MyLibrary" >

<constructor params="int, int" onLibrary="true" nativeName="MSC:?create@MyCPPClassOnDLL@@SGPAV1@HH@Z;gcc:_ZN15MyCPPClassOnDLL6createEii"> </constructor>

<method name="destroy" params="MyCPPClassOnDLL" onLibrary="true" nativeName="MSC:?destroy@MyCPPClassOnDLL@@SGXPAV1@@Z;gcc:_ZN15MyCPPClassOnDLL7destroyEPS_"> </method>

<method name="addStatic" params="int,int" onLibrary="true" nativeName="MSC:?addStatic@MyCPPClassOnDLL@@SG_JHH@Z;gcc:_ZN15MyCPPClassOnDLL9addStaticEii">

<method name="sub" params="int, int" onLibrary="true" nativeName="MSC:?sub@MyCPPClassOnDLL@@UAGNHH@Z;gcc:_ZN15MyCPPClassOnDLL3subEii">

<method name="varargsEx" onLibrary="true" nativeName="MSC:?varargsEx@MyCPPClassOnDLL@@SAXPADZZ;gcc:_ZN15MyCPPClassOnDLL9varargsExEPcz" callConv="c_call">
<return />
<param class="byte[]" />
<param class="Object[]" varargs="true" />

The following attribute:


...explains to JNIEasy to use "?create@MyCPPClassOnDLL@@SGPAV1@HH@Z" as the exported method name, if the native library was compiled with a Microsoft C/C++ compiler. Otherwise it uses "_ZN15MyCPPClassOnDLL6createEii", if compiled with gcc.

Both "macros" are user-defined, calling NativeTypeManager.defineMacro(String,Object). Using this "C-inspired" macro system allows JNIEasy, at runtime, to resolve the appropiated library name, method name, memory size, and so on. This way, Java "native" code can be portable between platforms, compilers, and so on.

Note that the getValue() method is not declared in the XML enhancer file. JNIEasy keeps this method "untouched". By default, any Java field in the class is declared native and bound to the C++ field by the enhancer. Correspondence between Java and C++ is according to the native layout of the class. This is the reason for the Java field "virtualTable", because the C++ class has a hidden member pointer to resolve virtual method addressing. And our C++ class has a virtual method, this implies a virtual method table.

This Java code shows an example of how we can access our C++ code and create a C++ object from Java:

long res = MyCPPClassOnDLL.addStatic(1,2);
System.out.println("Must be 3: " + res);

MyCPPClassOnDLL obj = new MyCPPClassOnDLL(1,2); // Calls create() C++ method.
// New object is already native and maps the C++ object
System.out.println("Must be 3: " + obj.getValue());
// Java method getValue() is not native (but field "value" is native)

double res2 = obj.sub(1,2);
System.out.println("Must be 0: " + res2);

MyCPPClassOnDLL.destroy(obj); // Calls the C++ method destroy(), the memory is freed.

This code is basically the same when we do the same in C++.

The call obj.getValue() is interesting, in spite of getValue() is not a “native” method (is a normal Java method) it returns the value of the C++ field “value”. The Java field “value” is a proxy of the C++ field, if the Java field is modified from Java (inside the Java class) the native field is automatically modified too (the Java class is enhanced to provide this transparency).

This example shows a C++ class ready to be used with JNIEasy (methods are exported with standard or C call convention, this is not the C/C++ default). Methods of legacy C++ classes can be exported and “wrapped” using false C++ methods. A chapter in manual (“MAPPING NATIVE LEGACY CLASSES”) shows how to do this.

Furthermore from C++ we can bind and call Java methods using normal pointer to functions:

double (__stdcall * MyCPPClassOnJava::_sub)(void*,int,int) = 0;
_sub = (double (__stdcall *)(void*,int,int)) JNIEasyHelper::findExportedMethodAddress("examples.manual.MyCPPClassOnJava.sub(int,int)");

This way we can define C++ classes as wrappers of Java POJOs.

The following call:

MyCPPClassOnJava* obj = …
_sub(obj, a, b);

Where “obj” points to a C++ MyCPPClassOnJava object (a C++ wrapper of the Java class) invokes the Java instance method sub(int,int) of the Java class MyCPPClassOnJava (this class must be previously declared as native with JNIEasy and loaded from Java).

An example of a Java class MyCPPClassOnJava:

public class MyCPPClassOnJava
protected double value;

public MyCPPClassOnJava() // mandatory

public MyCPPClassOnJava(int a,int b)
this.value = a + b;

JNIEasy.get().getLockedRegistry().lock(this); // To avoid GC if called from native

public static void destroy(MyCPPClassOnJava obj)
JNIEasy.get().getLockedRegistry().unlock(obj); // To enable GC again

public static long addStatic(int a,int b)
return (long)a + (long)b;

public double sub(int a,int b)
this.value = this.value - (a + b);
return this.value;

MyCPPClassOnJava methods can be exported as callbacks to the native world with the following XML enhancer descriptor:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Archive MyCPPClassOnJava.jnieasy.enh.xml -->
<jniEasyEnhancer version="1.1">

<package name="examples.manual">
<imports />
<class name="MyCPPClassOnJava" type="class">
<constructor exportMethod="true" params="int,int">
<method name="destroy" exportMethod="true"
<method name="addStatic" exportMethod="true" params="int,int">
<method name="sub" exportMethod="true" params="int,int">
<fieldMethod name="value" exportMethod="true" />

These examples show the "transparent" level. JNIEasy provides many utility classes too to attain fine-grained control in the Java-native world.

The current JNIEasy version is 1.2.1. This version runs on the following x86 platforms: Windows, Linux, MacOSX (including Leopard) and Solaris. JNIEasy is commercial software, but is free for non-profit usage via temporary licenses, which can be renewed without user data. Also note that LAMEOnJ, an open source Java based wrapper of the LAME API, using JNIEasy, has been updated to JNIEasy 1.2.1, adding Solaris x86 support.

You are welcome to download the library, also for the temporary license, and you can also visit the related Home page. So... maybe the time has come to bring your venerable native programs/libraries to Java, on a path into the future? And a question to readers: what native libraries do you know of that could be interesting to access from Java?


The Java Zone is brought to you in partnership with ZeroTurnaround. Discover how you can skip the build and redeploy process by using JRebel by ZeroTurnaround.


{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}