I'm using SWIG to make a Java wrapper of a C++ library (about Json (de)serialization) to use it on Android. I defined an abstract class in C++, representing an object which can be (de)serialized :
class IJsonSerializable {
public:
virtual void serialize(Value &root) = 0;
virtual void deserialize(Value &root) = 0;
};
Now, I'm trying to generate from this class a Java interface. Here's my SWIG interface:
%module JsonSerializable
%{
#include "JsonSerializable.hpp"
%}
%import "JsonValue.i"
class IJsonSerializable {
public:
virtual void serialize(Value &root) = 0;
virtual void deserialize(Value &root) = 0;
};
But the generated Java code is (obviously, as I was not able to find out how to tell SWIG that's an interface) a simple class, with the two methods and a default constructor/destructor:
public class IJsonSerializable {
private long swigCPtr;
protected boolean swigCMemOwn;
public IJsonSerializable(long cPtr, boolean cMemoryOwn) {
swigCMemOwn = cMemoryOwn;
swigCPtr = cPtr;
}
public static long getCPtr(IJsonSerializable obj) {
return (obj == null) ? 0 : obj.swigCPtr;
}
protected void finalize() {
delete();
}
public synchronized void delete() {
if (swigCPtr != 0) {
if (swigCMemOwn) {
swigCMemOwn = false;
JsonSerializableJNI.delete_IJsonSerializable(swigCPtr);
}
swigCPtr = 0;
}
}
public void serialize(Value root) {
JsonSerializableJNI.IJsonSerializable_serialize(swigCPtr, this, Value.getCPtr(root), root);
}
public void deserialize(Value root) {
JsonSerializableJNI.IJsonSerializable_deserialize(swigCPtr, this, Value.getCPtr(root), root);
}
}
How can I generate a valid interface with SWIG ?
You can achieve what you're looking for with SWIG+Java using "Directors", however it's not quite as straightforward mapping from the C++ abstract classes onto Java as you might hope. My answer therefore is split into three parts - firstly the simple example of implementing a C++ pure virtual function in Java, secondly an explanation of why the output is like that and thirdly a "work-around".
Implementing a C++ interface in Java
Given a header file (module.hh):
#include <string>
#include <iosfwd>
class Interface {
public:
virtual std::string foo() const = 0;
virtual ~Interface() {}
};
inline void bar(const Interface& intf) {
std::cout << intf.foo() << std::endl;
}
We'd like to wrap this and make it work intuitively from the Java side. We can do this by defining the following SWIG interface:
%module(directors="1") test
%{
#include <iostream>
#include "module.hh"
%}
%feature("director") Interface;
%include "std_string.i"
%include "module.hh"
%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary("module");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. \n" + e);
System.exit(1);
}
}
%}
Here we've enabled directors for the whole module, and then requested they be used for class Interface specifically. Other than that and my favourite "load the shared object automatically" code there's nothing particularly noteworthy. We can test this with the following Java class:
public class Run extends Interface {
public static void main(String[] argv) {
test.bar(new Run());
}
public String foo() {
return "Hello from Java!";
}
}
We can then run this and see it's working as expected:
ajw#rapunzel:~/code/scratch/swig/javaintf > java Run
Hello from Java!
If you're happy with it being neither abstract nor an interface you can stop reading here, directors do everything you need.
Why does SWIG generate a class instead of an interface?
SWIG has however made what looked like an abstract class into a concrete one. That means on the Java side we could legally write new Interface();, which makes no sense. Why does SWIG do this? The class isn't even abstract, let alone an interface (See point 4 here), which would feel more natural on the Java side. The answer is twofold:
SWIG supplies mechanics for calling delete, manipulating the cPtr etc. on the Java side. That couldn't be done in an interface at all.
Consider the case where we wrapped the following function:
Interface *find_interface();
Here SWIG knows nothing more about the return type than that it's of type Interface. In an ideal world it would know what the derived type is, but from the function signature alone there's no way for it to figure this out. This means that in the generated Java somewhere there's going to have to be a call to new Interface, which wouldn't be possible/legal if Interface were abstract on the Java side.
Possible workaround
If you were hoping to provide this as an interface in order to express a type hierarchy with multiple inheritance in Java this would be quite limiting. There's a workaround however:
Manually write the interface as a proper Java interface:
public interface Interface {
public String foo();
}
Modify the SWIG interface file:
Rename the C++ class Interface to be NativeInterface on the Java side. (We ought to make it visible only to the package in question too, with our wrapped code living in a package of its own to avoid people doing "crazy" things.
Everywhere we have an Interface in C++ code SWIG will now be using NativeInterface as the type on the Java side. We need typemaps to map this NativeInterface in function parameters onto the Interface Java interface we added manually.
Mark NativeInterface as implementing Interface to make the Java side behaviour natural and believable to a Java user.
We need to supply a little bit of extra code that can act as a proxy for things which implement the Java Interface without being a NativeInterface too.
What we pass to C++ must always be a NativeInterface still, not all Interfaces will be one though (although all NativeInterfaces will), so we provide some glue to make Interfaces behave as NativeInterfaces, and a typemap to apply that glue. (See this document for a discussion of the pgcppname)
This results in a module file that now looks like:
%module(directors="1") test
%{
#include <iostream>
#include "module.hh"
%}
%feature("director") Interface;
%include "std_string.i"
// (2.1)
%rename(NativeInterface) Interface;
// (2.2)
%typemap(jstype) const Interface& "Interface";
// (2.3)
%typemap(javainterfaces) Interface "Interface"
// (2.5)
%typemap(javain,pgcppname="n",
pre=" NativeInterface n = makeNative($javainput);")
const Interface& "NativeInterface.getCPtr(n)"
%include "module.hh"
%pragma(java) modulecode=%{
// (2.4)
private static class NativeInterfaceProxy extends NativeInterface {
private Interface delegate;
public NativeInterfaceProxy(Interface i) {
delegate = i;
}
public String foo() {
return delegate.foo();
}
}
// (2.5)
private static NativeInterface makeNative(Interface i) {
if (i instanceof NativeInterface) {
// If it already *is* a NativeInterface don't bother wrapping it again
return (NativeInterface)i;
}
return new NativeInterfaceProxy(i);
}
%}
Now we can wrap a function like:
// %inline = wrap and define at the same time
%inline %{
const Interface& find_interface(const std::string& key) {
static class TestImpl : public Interface {
virtual std::string foo() const {
return "Hello from C++";
}
} inst;
return inst;
}
%}
and use it like:
import java.util.ArrayList;
public class Run implements Interface {
public static void main(String[] argv) {
ArrayList<Interface> things = new ArrayList<Interface>();
// Implements the interface directly
things.add(new Run());
// NativeInterface implements interface also
things.add(test.find_interface("My lookup key"));
// Will get wrapped in the proxy
test.bar(things.get(0));
// Won't get wrapped because of the instanceOf test
test.bar(things.get(1));
}
public String foo() {
return "Hello from Java!";
}
}
This now runs as you'd hope:
ajw#rapunzel:~/code/scratch/swig/javaintf > java Run
Hello from Java!
Hello from C++
And we've wrapped an abstract class from C++ as an interface in Java exactly as a Java programmer would expect!
Related
Does C++ support anonymous implementation of interface like Java?
Something similar like in following code:
Runnable myRunnable =
new Runnable(){
public void run(){
System.out.println("Runnable running");
}
}
You can get pretty close by creating an instance of an anonymous class that inherits from your defined interface.
Example:
#include <iostream>
struct Runnable {
virtual ~Runnable() = default;
virtual void operator()() = 0;
};
int main() {
struct : Runnable { // anonymous implementation of interface
void operator()() override {
std::cout << "Run Forrest\n";
}
} myRunnable;
myRunnable(); // prints Run Forrest
}
Here's a contrived example, putting base class pointers to instances of different anonymous implementations of Runnable in a std::vector<std::unique_ptr<Runnable>>. As you can see here, making the implementations anonymous serves little purpose. The anonymous type is simply std::remove_reference_t<decltype(*instance)>.
#include <iostream>
#include <memory>
#include <type_traits>
#include <vector>
// Runnable is defined as in the example above
int main() {
// a collection of Runnables:
std::vector<std::unique_ptr<Runnable>> runners;
{ // create a pointer to an instance of one anonymous impl.
struct : Runnable {
void operator()() override {
std::cout << "Foo\n";
}
} *instance = new std::remove_reference_t<decltype(*instance)>;
runners.emplace_back(instance); // save for later
}
{ // create a pointer to an instance of another anonymous impl.
struct : Runnable {
void operator()() override {
std::cout << "Bar\n";
}
} *instance = new std::remove_reference_t<decltype(*instance)>;
runners.emplace_back(instance); // save for later
}
// loop through all `Runnable`s and ... run them:
for(auto& runner : runners) (*runner)(); // prints "Foo\nBar\n"
}
Does c++ support anonymous implementation of interface like java?
No, it does not. You must explicitly define an implementation class to inherit from the interface and override its virtual methods, eg:
class MyRunnableImpl : public Runnable {
public:
void run() override {
std::cout << "Runnable running";
}
};
Runnable *myRunnable = new MyRunnableImpl;
...
delete myRunnable;
No. C++ does not have this feature. C++ has different solutions for the problems that Java solves with such on-the-fly implementations of interfaces. Though, having accepted that, maybe we can still learn something by considering how it could be emulated in C++
#include <iostream>
#include <type_traits>
struct Runnable {
virtual void run() = 0;
virtual ~Runnable() = default;
};
template <typename F>
auto make_runnable(F f){
struct Runnable_Impl : Runnable {
F f;
Runnable_Impl(F f) : f(f) {}
void run() override {
f();
}
};
return Runnable_Impl{f};
}
void foo(Runnable& r){ r.run(); }
int main(){
auto runnable = make_runnable( [](){ std::cout << "hello world\n";});
runnable.run();
foo(runnable);
auto runn2 = make_runnable( [](){ std::cout << "hello world\n";});
std::cout << std::is_same_v<decltype(runnable),decltype(runn2)>;
}
Output:
hello world
hello world
0
Inside make_runnable the type has a name, but because each lambda expression is of different type, a call to make_runnable with a different lambda will yield a different type as you can see by comparing the types of the returned objects (is_same yields false). It could be anonymous, but as the caller doesn't get to see the name, that doesn't matter that much.
I haven't seen this or similar in the wild, though thats not a big surprise because C++ relies much less on interfaces and inheritance than Java.
We are using SWIG to create the JNI API between C++ API to Java in Android.
So for example lets say that our C++ class is:
class TestAnnotation {
public:
void setMessage(char * message);
char * getMessage();
private:
char* message = nullptr;
};
SWIG produces this auto generated Java class:
public class TestAnnotation {
...
public void setMessage(String message) {
myJNI.TestAnnotation_setMessage(swigCPtr, this, message);
}
public String getMessage() {
return myJNI.TestAnnotation_getMessage(swigCPtr, this);
}
}
As you can see, message can be null and it is possible for the get & set methods to receive/return a null String (the JNI auto generated code behaves as expected in this case and allows to either use jstring or null).
My question is whether: SWIG is capable of adding annotations like #Nullable or #NonNull to match the C++ API (if we need to supply "hints" to SWIG, that would also work).
So in this case the desired auto generated Java API will be:
public class TestAnnotation {
...
public void setMessage(#Nullable String message) {
myJNI.TestAnnotation_setMessage(swigCPtr, this, message);
}
#Nullable
public String getMessage() {
return myJNI.TestAnnotation_getMessage(swigCPtr, this);
}
}
This is important as we are using this Java API with Kotlin and the absence of the annotations make it harder to use the Kotlin smart features.
Give your example C++ class in a file called test.h you can generate a Java wrapper with the annotations you wanted using this syntax:
%module test
%javamethodmodifiers TestAnnotation::getMessage() %{
#Nullable
public%};
%typemap(jstype) char *message "#Nullable String";
%include "test.h"
It's a little counter intuitive given the naming focuses on other uses cases, but totally sensible usage nonetheless.
You can of course make the typemap for the inputs less specific by not naming the parameter in it (e.g. %typame(jstype) char * "...").
And you'll want to use another typemap to set up the imports:
%typemap(javaimports) TestAnnotation %{
import android.support.annotation;
%}
Which can be made more generic with:
%typemap(javaimports) SWIGTYPE %{
import android.support.annotation;
%}
I have a C++ library that I have to use in an existing Android implementation. I'm using Android NDK and using the C++ classes via JNI.
However, I am not able to find how to subclass a C++ abstract class in Java using JNI.
Problems I face:
My aim is to provide Java implementation for the virtual methods in C++ by subclassing the abstract C++ class.
I have loaded the native library and I'm trying to declare the native methods.
The C++ methods have keyword 'virtual'. When I declare the native functions in Java after loading the C++ library, 'virtual' is not recognized. What is wrong here?
Any help is appreciated. I'm a newbie to JNI. Thanks in advance.
Let's consider we have a C++ class:
class iVehicle
{
public:
virtual void Run() {}; // not-pure virtual here for simplicity of a wrapper, but could be pure (see the end of the post)
virtual int GetSize() const; // we want to reuse it in Java
};
We want to create a class Bot in Java that extends class iVehicle in the sense that calls to super invoke the C++ code from iVehicle::GetSize() and, from the C++ point of view, we can use the instances of Bot as iVehicle* variables. That's tough since C++ provides no good built-in functionality for reflection.
Here is one possible solution.
To use C++ class in Java we need to generate a Java wrapper, i.e:
class iVehicle
{
public void Run() { Native_Run(); }
public int GetSize() { return Native_GetSize(); }
private native void Native_Run();
private native int Native_GetSize();
// typecasted to pointer in C++
private int NativeObjectHolder;
// create C++ object
native static private int CreateNativeObject();
}
The usage in Java is simple:
class Bot extends iVehicle
{
public int GetSize()
{
if ( condition ) return 0;
// call C++ code
return super.GetSize();
}
}
However, there is a C++ part to this code:
static jfieldID gNativeObjectHolderFieldID;
JNIEXPORT void JNICALL Java_com_test_iVehicle_Run( JNIEnv* env, jobject thiz )
{
int Value = env->GetIntField(thiz, gNativeObjectHolderFieldID);
iVehicle* Obj = (iVehicle*)Obj;
// todo: add checks here, for NULL and for dynamic casting
Obj->Run();
}
The similar code is for GetSize().
Then creating an instance of Java's Bot you have to call CreateNativeObject() and assign the returned value to the NativeObjectHolder field.
JNIEXPORT int JNICALL Java_com_test_iVehicle_CreateNativeObject( JNIEnv* env, jobject thiz )
{
iVehicle* Obj = new iVehicle;
return (int)Obj;
}
So, this is the scheme. To make this work you will need to add the destruction code and to parse C++ classes to generate all this glue code.
Added:
In case where iVehicle is actually abstract you will have to generate a non-abstract wrapper that you are able to instantiate:
class iVehicle
{
virtual void Run() = 0;
}
class iVehicle_Wrapper: public iVehicle
{
virtual void Run() { ERROR("Abstract method called"); };
}
And instantiate iVehicle_Wrapper in CreateNativeObject(). Vuala! You have inherited an abstract C++ class in Java.
I have some code in C and one of the method has a function pointer as argument. I'm trying to use the C code in my Android app.
I decided to use SWIG to do all the work in generating the java files I need. Everything works well with regular function (the one that doesn't have a function pointer as argument).
But I'm not sure how I can pass my JAVA method as a callback to the C function.
Here is an example :
here is my multiply.h file
typedef int (*callback_t) (int a, int b, int c);
int foo(callback_t callback);
here is my multiply.c file
#include <stdio.h>
#include "multiply.h"
int foo(callback_t callback)
{
return callback(2, 4, 6);
}
here is my interface file multiply-swig.i
%module example
%{
/* Includes the header in the wrapper code */
#include "multiply.h"
%}
/* Parse the header file to generate wrappers */
%include "multiply.h"
then I ran the following swig command to generate the java files I need
swig -java -package com.example.ndktest -o multiply-wrap.c mulitiply-swig.i
and then swig generated the following files :
example.java
package com.example.ndktest;
public class example {
public static int foo(SWIGTYPE_p_f_int_int_int__int callback) {
return exampleJNI.foo(SWIGTYPE_p_f_int_int_int__int.getCPtr(callback));
}
}
exampleJNI.java
package com.example.ndktest;
public class exampleJNI {
public final static native int foo(long jarg1);
}
SWIGTYPE_p_f_int_int_int__int.java
package com.example.ndktest;
public class SWIGTYPE_p_f_int_int_int__int {
private long swigCPtr;
protected SWIGTYPE_p_f_int_int_int__int(long cPtr, boolean futureUse) {
swigCPtr = cPtr;
}
protected SWIGTYPE_p_f_int_int_int__int() {
swigCPtr = 0;
}
protected static long getCPtr(SWIGTYPE_p_f_int_int_int__int obj) {
return (obj == null) ? 0 : obj.swigCPtr;
}
}
Now how can I call this foo method from my java code? The argument is of type SWIGTYPE_p_f_int_int_int__int ??? I don't understand how I can pass a JAVA method as callback to the C code ... I think I am definitely missing something here ....
Any help is appreciated, thanks
Obviously, you cannot pass a single method as an argument. But callbacks are still possible with "Director" feature via implementing callback in an interface. See this example.
I compiled following JavaScript file, "test.js", into the "test.class" :
var test = (function () {
var that = {};
that.addNumbers = function (a, b) {
return a+b;
};
return that;
}());
I would like to call the compiled JavaScript function, "test.addNumbers(1,2)", in the simple Java program "run.java" as follows :
public class run {
public static void main(String[] args) throws Exception {
Context cx = Context.enter();
try {
Scriptable scope = cx.initStandardObjects();
// HOW TO CALL THE METHOD, Test.addNumbers(1,2)? Please help me!
} finally {
Context.exit();
}
}
}
I tried many ways, but failed. I read Rhino tutorial and examined many articles and examples, BUT they only show how to call JavaScript methods from the command line or the source file, "test.js".
I need to call the method from the compiled "test.class" file.
Thanks much in advance for your help!
Using javap, I believe that the JavaScript type test does not mean that the resultant Java type is this class. The generated Java type invokes the script code in its constructor; this will not result in exposing addNumbers as a Java method.
>javap -classpath . test
public class test extends org.mozilla.javascript.NativeFunction implements org.m
ozilla.javascript.Script{
public test(org.mozilla.javascript.Scriptable, org.mozilla.javascript.Contex
t, int);
public test();
public static void main(java.lang.String[]);
public final java.lang.Object exec(org.mozilla.javascript.Context, org.mozil
la.javascript.Scriptable);
public final java.lang.Object call(org.mozilla.javascript.Context, org.mozil
la.javascript.Scriptable, org.mozilla.javascript.Scriptable, java.lang.Object[])
;
public int getLanguageVersion();
public java.lang.String getFunctionName();
public int getParamCount();
public int getParamAndVarCount();
public java.lang.String getParamOrVarName(int);
public java.lang.String getEncodedSource();
public boolean getParamOrVarConst(int);
}
Reading between the lines, I'd say you need to map to Java types to do what you want. From the jsc doc:
-implements java-intf-name
Specifies that a java class
implementing the Java interface
java-intf-name should be generated
from the incoming JavaScript source
file. Each global function in the
source file is made a method of the
generated class, implementing any
methods in the interface by the same
name.
Define this interface:
//Adder.java
public interface Adder {
public int addNumbers(int a, int b);
}
Write this implementation:
//AdderImpl.js
function addNumbers(a, b) {
return a+b;
}
Compile the JavaScript with the arguments -implements Adder AdderImpl.js. Invoke the method like so:
Adder adder = new AdderImpl();
int n = adder.addNumbers(1, 2);
System.out.println(n);
I'd hazard a guess that it was probably necessary to do it this way because of differences in the languages' type systems.
I used Rhino 1.7R2. For the sake of brevity, I've avoided using packages, etc.