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.
Related
I am trying to migrate the python library into the java native script but I facing extreme complexity with the parameters while migration.
Here the code I need to migrate the python method with the default & optional parameters with different datatypes into the java method:
def connect_network(self,
bssid=None,
proto="http",
check_redirect_code=True,
redirect_code='302',
portal_url=None,
subscriber_portal='scg',
expect_href_list_zd_sp='google',
check_user_block=False,
redirect_url='',
tnc_content="",
path="/tmp/"):
pass
Here is my example code which I tried in java equivalent:
public class LinuxClientUtils {
public void DefaultNameParameter1(HashMap<Integer, String> params){
System.out.Println(params.toString());
}
public void DefaultNameParameter2(Map.Entry<String, String>... params){
System.out.Println(params.toString());
}
public void DefaultNameParameter3(Optional<String> name, Optional<String> age){
System.out.Println(name.toString());
}
}
I will import that Java library in the robot framework and call the method like this,
*** Settings ***
Library test.LinuxClientUtils
*** Test Cases ***
Testing
[tags] service
[Documentation] Add Network
Default Name Parameter3 req_network_id=89
Still, None of the methods didn't work.
I have tried few Methods from the following URLs Link-1
Link-2 But I am unable to figure it out from those links.
I'm new to JAVA programming and haven't been able to fix this one. Any help would be great, thanks.
Create a new class for a parameter object. It will have each of the parameters as a field.
The constructor of this parameter class has no parameters. Instead, each field has a default value. (null and false are automatically assigned by default for object and boolean fields, anyway.)
Your function will just take a parameter object as a single parameter.
public class A {
static class ParameterObject {
public ParameterObject(){
//empty
}
private int x;
private boolean b;
private String s;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public boolean isB() {
return b;
}
public void setB(boolean b) {
this.b = b;
}
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
}
public static void f(ParameterObject o){
//Do something with object
}
public static void main(String[] args) {
ParameterObject paramObj=new ParameterObject();
paramObj.setX(10);
f(paramObj);
}
}
Golang
import "C"
//export MyFunction
func MyFunction(str *C.char) *C.char {
goStr := C.GoString(str)
msg := goStr + " world"
return C.CString(msg)
}
func main() {}
Java
public interface MyLib extends Library {
MyLib INSTANCE = Native.load("mylib.so", MyLib.class);
String MyFunction(String str);
}
public class CGoExample {
public static void main(String[] args) {
String str = "Hello";
String msg = MyLib.INSTANCE.MyFunction(str);
System.out.println(msg);
}
}
This code works, the Java String is passed to Go, and Go returns a new String. The issue I'm having is that the CString returned by Go will not be deallocated by either the Java or Go garbage collector. The CGO documentation states "it is the caller's responsibility to arrange for it to be freed, such as by calling C.free", of course in my case calling C.free will not work as I'm returning the CString and if I free the CString before returning it I don't get a proper response from the Go function. I also tried calling defer C.free(unsafe.Pointer(msg)) but as I found out the hard way defer statements will be called before the return statement.
As I need to return the CString I'm assuming its memory needs to be deallocated from java, how would I go about doing this?
Edit:
Based on DanielWiddis' comment I have tried the following but the java process exists with code -1073741819.
// #include <stdlib.h>
import "C"
import "unsafe"
//export MyFunction
func MyFunction(str *C.char) *C.char {
goStr := C.GoString(str)
msg := goStr + " world"
return C.CString(msg)
}
//export Free
func Free(str *C.char){
C.free(unsafe.Pointer(str))
}
func main() {}
public interface MyLib extends Library {
MyLib INSTANCE = Native.load("mylib.so", MyLib.class);
String MyFunction(String str);
void Free(String str);
}
public class CGoExample {
public static void main(String[] args) {
String str = "Hello";
String msg = MyLib.INSTANCE.MyFunction(str);
System.out.println(msg);
MyLib.INSTANCE.Free(msg);
}
}
The return type of C.CString() is a pointer: *C.char.
By mapping this directly to a String on the Java side, you are losing track of that native Pointer, making it impossible to track and free it later.
The most straightforward solution is just to map that to a Pointer on the Java side. In the interface:
Pointer MyFunction(String str);
void Free(Pointer str);
Then to use it:
Pointer pMsg = MyLib.INSTANCE.MyFunction(str);
System.out.println(pMsg.getString(0));
MyLib.INSTANCE.Free(pMsg);
It's possible a byte[] array of (8 bit) characters would also work in this situation. Personally, I'd probably use a type safe pointer with some object oriented helper methods such as:
class CStringPtr extends PointerType {
public CStringPtr(String str) {
super(MyLib.INSTANCE.MyFunction(str));
}
public String getString() {
return this.getPointer().getString(0);
}
public void free() {
MyLib.INSTANCE.Free(this.getPointer());
}
}
which would make your code:
CStringPtr pMsg = new CStringPtr(str);
System.out.println(pMsg.getString());
pMsg.free();
Based on DanielWiddis' comments I came up with the following solution which successfully deallocates memory for all involved objects.
package main
// #include <stdlib.h>
import "C"
import (
"unsafe"
)
//export MyFunction
func MyFunction(cStr *C.char) *C.char {
str := C.GoString(cStr)
msg := str + " world"
return C.CString(msg)
}
//export Free
func Free(str *C.char){
C.free(unsafe.Pointer(str))
}
func main() {}
public interface MyLib extends Library {
MyLib INSTANCE = Native.load("mylib.so", MyLib.class);
Pointer MyFunction(Pointer ptr);
void Free(Pointer ptr);
}
public class CGoExample {
public static void main(String[] args) {
// Create pointer with a String value
String str = "Hello";
Pointer ptr = new Memory(str.length() + 1);
ptr.clear();
ptr.setString(0, str);
//Pass the pointer to Go function which returns the pointer of the message
Pointer resultPtr = MyLib.INSTANCE.MyFunction(ptr);
//Get the message String from the pointer
String msg = resultPtr.getString(0);
//Deallocate the memory for the message
MyLib.INSTANCE.Free(resultPtr);
System.out.println(msg);
}
}
Lambda is used here, but when ::new is used, the following parameters are populated into the constructor:
#FunctionalInterface
interface Lambdademo1<T> {
T test(String s);
}
class Test {
public static void test2(Lambdademo1<Apple> lambdademo1, String s) {
Apple i = lambdademo1.test(s);
System.out.println(i.getColor());
}
public static void main(String args[]){
test2(Apple::new,"hehehe");
}
}
Output:
hehehe
UPDATE:
class test {
public static void main(String args[]) {
test1((String s) -> new Integer(1), "hehehe");
test1(Integer::new, "hehehe"); //It's wrong
test2(Apple::new,"hehehe");
test3(Apple1::new,"hehehe"); //Compile error
// I think XXX::new is equivalen to new XXX() but here shoe it's not
}
public static void test1(Lambdademo1<Integer> lambdademo1, String s) {
Integer i = lambdademo1.test(s);
System.out.println(i);
}
public static void test2(Lambdademo1<Apple> lambdademo1, String s) {
Apple i = lambdademo1.test(s);
System.out.println(i.getColor());
}
public static void test3(Lambdademo1<Apple1> lambdademo1, String s) {
Apple1 i = lambdademo1.test(s);
System.out.println(i.getColor());
}
}
The Apple1 class:
class Apple1 {
private String color;
// getter and setter
}
The Apple class:
class Apple {
private String color;
public Apple(String color) {
this.color = color;
}
// getter and setter
}
Original answer
Apple::new can (and does) refer to a constructor Apple(String) because it follows the contract of T test(String s) - (String string) -> new Apple(string); or Apple:new
Apparently, that constructor sets the value for the color field since the getter returns the value you passed to the constructor.
test2(Apple::new,"hehehe");
is equivalent to
System.out.println(new Apple("hehehe").getColor());
Update
Let's discuss each line in detail to make it clear.
1.
test1((String s) -> new Integer(1), "hehehe");
You are taking a String s, not using it, and returning a constant new Integer(1) or simply 1.
We might rewrite it to
test1(s -> 1,"hehehe" );
2.
test1(Integer::new, "hehehe");
It's not wrong. It's absolutely compilable line. There is a constructor Integer(String s) that converts the given String to an int using Integer.parseInt(String).
Since "hehehe" isn't a parsable int, you will get a NumberFormatException, but that's a runtime issue.
3.
It's fine, and I have explained it in the original answer above.
4.
test3(Apple1::new,"hehehe");
You haven't defined any constructors for Apple1, so we have the no-arguments one by default. Since it doesn't take a String, we can't use it to represent Lambdademo1#test.
Writing a lambda will make it compile, though.
test3(s -> new Apple1(),"hehehe");
I think XXX::new is equivalent to new XXX() but here it's not.
It depends on context. XXX::new always refers to a constructor. What constructor? We don't know it until we see the context.
Examine an example where Apple::new points at 3 different constructors.
class Apple {
public Apple() {}
public Apple(Integer i) {}
public Apple(String s) {}
public static void main(String[] args) {
Supplier<Apple> a = Apple::new;
Function<Integer, Apple> b = Apple::new;
Function<String, Apple> c = Apple::new;
}
}
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.
Is there a way to create a Lua function in Java and pass it to Lua to assign it into a variable?
For example:
In my Java class:
private class doSomething extends ZeroArgFunction {
#Override
public LuaValue call() {
return "function myFunction() print ('Hello from the other side!'); end" //it is just an example
}
}
In my Lua script:
myVar = myHandler.doSomething();
myVar();
In this case, the output would be: "Hello from the other side!"
Try using Globals.load() to construct a function from a script String, and use LuaValue.set() to set values in your Globals:
static Globals globals = JsePlatform.standardGlobals();
public static class DoSomething extends ZeroArgFunction {
#Override
public LuaValue call() {
// Return a function compiled from an in-line script
return globals.load("print 'hello from the other side!'");
}
}
public static void main(String[] args) throws Exception {
// Load the DoSomething function into the globals
globals.set("myHandler", new LuaTable());
globals.get("myHandler").set("doSomething", new DoSomething());
// Run the function
String script =
"myVar = myHandler.doSomething();"+
"myVar()";
LuaValue chunk = globals.load(script);
chunk.call();
}