I want to access a Java graph library (Titan) from c++. Doing some research showed that JNI would get the job done. I wrote some JNI code, got it working, but it quickly became tedious, so I looked to an automated solution. I found SWIG, more specifically SWIG directors. I have no problem calling functions, however I have a problem of maintaining state going back and forth from Java and c++ using a SWIG director.
For my SWIG directors I wrote c++ interfaces exposing the functionality I wanted. Below is a sample:
GraphIfc.hpp:
struct GraphIfc {
virtual ~GraphIfc() {}
virtual VertexIfc * addVertex(const std::string& label) = 0;
};
VertexIfc.hpp:
struct VertexIfc {
virtual ~VertexIfc() {}
virtual EdgeIfc * addEdge(const std::string& label, VertexIfc * v) = 0;
};
EdgeIfc.hpp:
struct EdgeIfc {
virtual ~EdgeIfc() {}
};
Then I wrote the Java implementation:
JGraph.java:
import com.thinkaurelius.titan.core.TitanGraph;
public class JGraph extends GraphIfc {
private TitanGraph graph;
public JGraph(TitanGraph g) {
graph = g;
}
public VertexIfc addVertex(final String label) {
return new Vertex(graph.addVertex(label));
}
}
JVertex.java:
import com.thinkaurelius.titan.core.TitanVertex;
public class JVertex extends VertexIfc {
public TitanVertex vertex;
public JVertex(TitanVertex v) {
vertex = v;
}
public EdgeIfc addEdge(final String label, VertexIfc inV) {
Vertex v = (Vertex)inV;
return new Edge(vertex.addEdge(label, v.vertex));
}
}
JEdge.java:
import org.apache.tinkerpop.gremlin.structure.Edge;
public class JEdge extends EdgeIfc {
public Edge edge = null;
public JEdge(Edge e) {
edge = e;
}
}
And here's my SWIG file:
%module(directors="1") graph
%{
#include "graph.hpp"
#include "vertex.hpp"
#include "edge.hpp"
%}
%feature("director") GraphIfc;
%feature("director") VertexIfc;
%feature("director") EdgeIfc;
SWIG_DIRECTOR_OWNED(GraphIfc)
SWIG_DIRECTOR_OWNED(VertexIfc)
SWIG_DIRECTOR_OWNED(EdgeIfc)
%include "graph.hpp"
%include "vertex.hpp"
%include "edge.hpp"
%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary("graph");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library graph failed to load.\n" + e);
System.exit(1);
}
}
%}
All of this produces:
Java proxy classes: GraphIfc, VertexIfc, EdgeIfc. These hold the c++ pointer as a long.
Intermediary JNI class in Java with functions
such as:
public static long SwigDirector_GraphIfc_addVertex(GraphIfc jself, String label) {
return VertexIfc.getCPtr(jself.addVertex(label));
}
public static long SwigDirector_VertexIfc_addEdge(VertexIfc jself, String label, long inVertex) {
return EdgeIfc.getCPtr(jself.addEdge(label, (inVertex == 0) ? null : new VertexIfc(inVertex, false)));
}
There are a two problems with these functions:
The VertexIfc being created by SwigDirector_VertexIfc_addEdge is not of type JVertex, thus my cast within addEdge will fail and throw an exception.
But more importantly, even if the type was a JVertex, the new JVertex would not contain the same value of TitanVertex as set by addVertex. Any state within the derived class (JVertex, JEdge, etc) is loss.
Related
I am converting the source code from JAVA (working) to C++. Although I have very little experience in C++, I have managed to convert most of the code but I can't find the equivalent of import java.util.LinkedList; in C++. At the moment of compiling I get an error in these lines. Does anyone have any idea how I can convert these functions?
Code in JAVA:
package co.unicauca.robotindustrial;
import java.util.LinkedList;
import java.util.List;
public abstract class RobotIndustrial{
protected List<Articulacion> arts;
protected List<Sensor> sensors;
protected List<Movimiento> movimientos;
public RobotIndustrial(){
arts = new LinkedList<>();
sensors = new LinkedList<>();
movimientos = new LinkedList<>();
}
public void addArticulacion(Articulacion a){
arts.add(a);
}
public void addSensor(Sensor s){
sensors.add(s);
}
public void addMovimiento(Movimiento m){
movimientos.add(m);
}
public void configurarRobot(){
this.armarRobot();
this.definirRecorrido();
}
public void action(){
for( Movimiento each: movimientos){
each.execute();
}
}
public abstract void definirRecorrido();
public abstract void armarRobot();
}
Code in C++
#pragma once
#include "Articulacion.h"
#include "Sensor.h"
#include "Movimiento.h"
#include <vector>
#include <list>
class RobotIndustrial
{
protected:
std::vector<Articulacion*> arts;
std::vector<Sensor*> sensors;
std::vector<Movimiento*> movimientos;
public:
RobotIndustrial()
{
arts = std::list<Articulacion>();
sensors = std::list<Sensor>();
movimientos = std::list<Movimiento>();
}
virtual void addArticulacion(Articulacion *a)
{
arts.push_back(a);
}
virtual void addSensor(Sensor *s)
{
sensors.push_back(s);
}
arts is std::list<Articulacion*>, you are assigning std::list<Articulacion>(). The same for sensors and movimientos. You should not initialize these variables, this looks like initializing the default value with the default value.
RobotIndustrial()
{
arts = std::list<Articulacion>();
sensors = std::list<Sensor>();
movimientos = std::list<Movimiento>();
}
should be
RobotIndustrial() = default;
i use jna 4.2.1
I have a method in the dll which returns a pointer to an object (C++)
basic_hash* getAlgorithmInstance( int algorithm )
basic_hash has the following methods (C++):
void reset ();
void partial (const byte* data, uint64 size);
void finalize (vector_byte& hash);
void hash (const byte* data, uint64 size, vector_byte& hash).
i have interface (java)
public interface HAL extends Library {
HAL INSTANCE = (HAL) Native.loadLibrary(
(Platform.isWindows() ? "HAL" : "libHAL"), HAL.class);
BasicHash getAlgorithmInstance(int i);
}
public static class BasicHash extends Structure {
public BasicHash() {}
public BasicHash(Pointer p) {
super(p);
read();
}
#Override
protected List getFieldOrder() {
return Arrays.asList(new String[] { "reset", "hash", "partial", "finalize" });
}
public interface Reset extends Callback { public void invoke();}
public Reset reset;
public interface Hash extends Callback {public void invoke(byte[] data, long size, byte[] hash);}
public Hash hash;
public interface Partial extends Callback {public void invoke(Pointer data, long size);}
public Partial partial;
public interface Finalize extends Callback {public void invoke(byte[] hash);}
public Finalize finalize;
}
and when I use the method without parameters in main()
HAL lib = HAL.INSTANCE;
BasicHash b = lib.getAlgorithmInstance(0);
b.reset.invoke();
I get an error:
Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeVoid(Native Method)
at com.sun.jna.Function.invoke(Function.java:374)
at com.sun.jna.Function.invoke(Function.java:323)
at com.sun.jna.Function.invoke(Function.java:275)
at com.sun.jna.CallbackReference$NativeFunctionHandler.invoke(CallbackReference.java:646)
at com.sun.proxy.$Proxy1.invoke(Unknown Source)
at net.erver.ItServer.main(ItServer.java:79)
Why did I receive this error if the method resets the variables within the library? the method itself fulfills without problems (according to developers dll)
EDIT:
vector_byte has definition:
typedef unsigned char byte;
typedef std::vector< byte > vector_byte
and basic_hash has definition:
namespace HAL { namespace algorithms {
HAL_HASH_API enum class State : byte {
Normal,
Finished,
};
class HAL_HASH_API basic_hash
{
public:
virtual ~basic_hash() {}
virtual void reset() = 0;
virtual void partial( const byte*, uint64 ) = 0;
virtual void finalize( vector_byte& ) = 0;
virtual void hash( const byte*, uint64, vector_byte& ) = 0;
bool isFinished() {
return ( _state == State::Finished ? true : false );
}
protected:
State _state;
};
}
}
You need to use plain vanilla struct to pass data between JNA and your library. A C++ class (including a vector template) has a much different memory layout than does a simple C struct.
I am working on a windows device manager which will work with java.
I stick on trying to pass without error SetupDiSetClassInstallParams function. (I am trying disable an device.)
I am running exact same structure(necessary way) in C++ and I do not have any problem.
I am getting ERROR_INVALID_USER_BUFFER error. When I tried get this error in C++ I need to change SP_PROPCHANGE_PARAMS structs values with wrong ones.
My struct declerations:
public static class SP_CLASSINSTALL_HEADER extends Structure {
public static class ByReference extends SP_CLASSINSTALL_HEADER implements Structure.ByReference {
public ByReference() {
}
public ByReference(Pointer memory) {
super(memory);
}
}
public SP_CLASSINSTALL_HEADER() {
cbSize = size();
}
public SP_CLASSINSTALL_HEADER(Pointer memory) {
super(memory);
read();
}
public int cbSize;
public long InstallFunction; **/* <-- this should be int or else buffer size changes, dll cannot place variables on right places. */**
protected List getFieldOrder() {
return Arrays.asList(new String[] { "cbSize", "InstallFunction" });
}
}
public static class SP_PROPCHANGE_PARAMS extends Structure {
public static class ByReference extends SP_PROPCHANGE_PARAMS implements Structure.ByReference {
public ByReference() {
}
public ByReference(Pointer memory) {
super(memory);
}
}
public SP_PROPCHANGE_PARAMS() {
}
public SP_PROPCHANGE_PARAMS(Pointer memory) {
super(memory);
read();
}
public SP_CLASSINSTALL_HEADER ClassInstallHeader = new SP_CLASSINSTALL_HEADER();
public int StateChange;
public int Scope;
public int HwProfile;
protected List getFieldOrder() {
return Arrays.asList(new String[] { "ClassInstallHeader", "StateChange", "Scope", "HwProfile" });
}
}
My function decleration:
boolean SetupDiSetClassInstallParams(WinNT.HANDLE hDevInfo, Pointer deviceInfoData, Pointer classInstallHeader, int size);
How do I calling this function:
SP_PROPCHANGE_PARAMS spPropChangeParams = new SP_PROPCHANGE_PARAMS();
spPropChangeParams.ClassInstallHeader.InstallFunction = DISetupApi.DIF_PROPERTYCHANGE;
spPropChangeParams.Scope = DISetupApi.DICS_FLAG_GLOBAL;
spPropChangeParams.HwProfile = 0;
spPropChangeParams.StateChange = DISetupApi.DICS_DISABLE;
int spPropChangeParamsSize = spPropChangeParams.size();
SP_CLASSINSTALL_HEADER classInstallHeaderReference = new SP_CLASSINSTALL_HEADER(spPropChangeParams.getPointer());
setupApi.SetupDiSetClassInstallParams(hDevInfo, device.getSPDeviceInfoData().getPointer(), classInstallHeaderReference.getPointer(),
spPropChangeParamsSize);
How It works in c++:
SP_PROPCHANGE_PARAMS spPropChangeParams;
spPropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
spPropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
spPropChangeParams.Scope = DICS_FLAG_GLOBAL;
spPropChangeParams.HwProfile = 0;
spPropChangeParams.StateChange = DICS_DISABLE;
SetupDiSetClassInstallParams(hDeviceInfo, &device.getDeviceInfoData(), (SP_CLASSINSTALL_HEADER*)&spPropChangeParams, sizeof(spPropChangeParams));
Actually I mixed and matched too many ways these structs and function I changed variable types of structs and parameter types of function at the end I could not get anything but error. I cannot find what is my mistake. Could you please help me solve this.
Thanks in advance!
When you're passing around a Structure, don't use Structure.getPointer() unless you have to. When you do that, JNA can't automatically synch the native and Java data, and it's error-prone to remember where to do that yourself. In your case, whatever is in the Java fields never gets copied to native memory in your call to setupApi.SetupDiSetClassInstallParams.
Change your function mapping to this:
boolean SetupDiSetClassInstallParams(WinNT.HANDLE hDevInfo, SP_DEVINFO_DATA deviceInfoData, SP_CLASSINSTALL_HEADER classInstallHeader, int size);
and change the invocation to this:
setupApi.SetupDiSetClassInstallParams(hDevInfo, device.getSPDeviceInfoData(), classInstallHeaderReference, spPropChangeParamsSize);
EDIT
If you stick to your original struct definition (where SP_CLASSINSTALL_HEADER is a field), you need to add a function mapping to the interface (extend the interface and create your own instance of the native library):
public interface MySetupApi extends SetupApi {
MySetupApi INSTANCE = (MySetupApi)Native.loadLibrary(MySetupApi.class, W32APIOptions.DEFAULT_OPTIONS);
boolean SetupDiSetClassInstallParams(WinNT.HANDLE hDevInfo, SP_DEVINFO_DATA deviceInfoData, SP_PROPCHANGE_PARAMS propChangeParams, int size);
}
I have on C side
typedef struct {} C_String;
C_String* StringNew();
void StringFree(C_String* string);
On Java I get such wrapper class
public class String {
private long swigCPtr;
protected boolean swigCMemOwn;
protected String(long cPtr, boolean cMemoryOwn) {
swigCMemOwn = cMemoryOwn;
swigCPtr = cPtr;
}
protected static long getCPtr(String obj) {
return (obj == null) ? 0 : obj.swigCPtr;
}
protected void finalize() {
delete();
}
public synchronized void delete() {
if (swigCPtr != 0) {
if (swigCMemOwn) {
swigCMemOwn = false;
JNI.delete_C_String(swigCPtr);
}
swigCPtr = 0;
}
}
public String() {
this(JNI.new_C_String(), true);
}
}
JNI.new_С_String and JNI.delete_С_String are native methods generated by SWIG, they do simple work - allocate C_String by malloc and delete it by free respectively. In my case scenario should be different, since C_String is empty structure and acts like shortcut proper way should be allocation by StringNew which has malloc under hood and freeing by StringFree.
I want to use proper methods instead of JNI.new_String, JNI.delete_String what the easiest method to achieve this?
Assuming the C you showed is in a file called test.h the following SWIG interface would do what you wanted:
%module test
%{
#include "test.h"
%}
%extend C_String {
C_String() {
return StringNew();
}
~C_String() {
StringFree($self);
}
}
%ignore StringNew;
%ignore StringFree;
%include "test.h"
This uses %extend to supply a custom constructor and destructor for the C_String type. This constructor/destructor pair just calls the C functions StringNew and StringFree respectively.
In your question you asked to have these calls happen from within the generated Java code. The way I've written it above makes these calls happen from within C instead. This has two primary benefits:
It is language neutral - the same interface file works equally well regardless of what language you're targeting.
It minimses calls between native and Java (or any other target) code. This is generally a good thing from a performance perspective since these cross-language jumps tend to be the most expensive part of your interface.
The remainder of this answer is mostly just here as a learning point and not a recommended solution.
If you really wanted to though you could write this as Java and make the JNI calls you asked for. To do this you would need to write a few typemaps, you would need at least two which (untested) might look something like:
javabody:
%typemap(javabody) C_String %{
private long swigCPtr;
protected boolean swigCMemOwn;
protected $javaclassname(long cPtr, boolean cMemoryOwn) {
swigCMemOwn = cMemoryOwn;
swigCPtr = cPtr;
}
public $javaclassname() {
$javaclassname tmp = $imclassname.StringNew();
swigCMemOwn = tmp.swigCMemoryOwn;
swigCPtr = tmp.swigCPtr;
tmp.swigCMemoryOwn = false;
}
protected static long getCPtr($javaclassname obj) {
return (obj == null) ? 0 : obj.swigCPtr;
}
%}
javadestruct:
%typemap(javabody) C_String %{
public synchronized void delete() {
if (swigCPtr != 0) {
if (swigCMemOwn) {
swigCMemOwn = false;
$imclassname.StringFree(swigCPtr);
}
swigCPtr = 0;
}
}
%}
But as noted previously this really isn't the best way to solve the problem. (You'd need a 'javadestruct_derived' typemap as well if you wanted this to still happen for cases with inheritance)
I have the following code in C++ (Cocos2d) :
typedef void (CCObject::*SEL_CallFunc)();
CCCallFunc * CCCallFunc::actionWithTarget(CCObject* pSelectorTarget,
SEL_CallFunc selector) {
CCCallFunc *pRet = new CCCallFunc();
if (pRet && pRet->initWithTarget(pSelectorTarget)) {
pRet->m_pCallFunc = selector;
pRet->autorelease();
return pRet;
}
CC_SAFE_DELETE(pRet);
return NULL;
}
When converting with swig to java I get the following :
public static CCCallFunc actionWithTarget(CCObject pSelectorTarget, SWIGTYPE_m_CCObject__f___void selector) {
long cPtr = cocos2dxMappingJNI.CCCallFunc_actionWithTarget(CCObject.getCPtr(pSelectorTarget), pSelectorTarget,
SWIGTYPE_m_CCObject__f___void.getCMemberPtr(selector));
return (cPtr == 0) ? null : new CCCallFunc(cPtr, false);
}
Where SWIGTYPE_m_CCObject__f___void is just a pointer I can't use.
How do I implement this in the SWIG interface ?
I've looked into this solution stackoverflow but couldn't implement it for my case.
I don't believe SWIG supports member function pointers in any meaningful way. However, it's possible to get it done with JavaCPP. Given this C++ code in a file named MemberFunction.h:
class MyClass {
public:
virtual ~MyClass() { }
};
typedef void (MyClass::*MyFunction)(const char *str);
void callback(MyClass* cls, MyFunction fct, const char *str) {
(cls->*fct)(str);
}
We can define and use the callback this way in Java:
import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;
#Platform(include="MemberFunction.h")
public class MemberFunction {
static { Loader.load(); }
public static abstract class MyClass extends Pointer {
public MyClass() { allocate(); }
private native void allocate();
#Virtual public abstract void myCallback(String str);
#Virtual #MemberGetter #Name("myCallback")
public static native MyFunction getMyCallback();
}
#Namespace("MyClass")
public static class MyFunction extends FunctionPointer {
public native void call(MyClass cls, String str);
}
public static native void callback(MyClass cls, MyFunction fct, String str);
public static void main(String[] args) {
MyClass cls = new MyClass() {
public void myCallback(String str) {
System.out.println(str);
}
};
MyFunction fct = MyClass.getMyCallback();
callback(cls, fct, "Hello World");
}
}
Which builds fine and outputs the expected result:
$ javac -cp javacpp.jar MemberFunction.java
$ java -jar javacpp.jar MemberFunction
$ java -cp javacpp.jar MemberFunction
Hello World
You probably want to look at a typemap for "SEL_CallFunc selector". The typemap squirrels the original language callback, which is called via a tramploline function. There are python examples here and here. You'll find various similar questions for java on SO.