2014-09-30 200 views
1

我試圖通過痛飲這兩個C++函數生成Java綁定痛飲類型映射Java對象

C++函數

void SetUserData(void* data); 
void* GetUserData() const; 

在Java端我希望它看起來像這樣

setUserData(Object object); 
getUserData() //return java.lang.Object 

我想void *指針指向我傳給它的任何java對象。在我痛飲文件我嘗試添加這些行

//swig file 
%typemap(jstype) void* "java.lang.Object"; 
%apply Object {void*}; 

我得到一個編譯錯誤: b2Fixture.swig(22):警告453:不能適用(對象)。沒有定義類型映射。我不知道如何爲此創建類型映射。有任何想法嗎?

回答

2

你可能想要做的:

%apply jobject { void* }; 

因爲申請%複印件上一個C++到另一種C++類型定義的typemaps。 Object是一種Java類型,不是C++類型,因此沒有任何類型映射可以被複制。另一方面,jobject是JNI等價物。

此外假設你想擁有「正常」 GC語義(即不要求保留您通過任何數據),你需要做更多的工作,例如:

%module test 

%{ 
#include "test.hh" 
%} 

%apply jobject { void * }; 

%typemap(in) void * { 
    void *old = getData(); 
    if (old) JCALL1(DeleteGlobalRef, jenv, (jobject)old); 
    $1 = JCALL1(NewGlobalRef, jenv, $input); 
} 

%typemap(out) void * { 
    $result = (jobject)($1); 
} 

%include "test.hh" 

這使得爲您的數據提供一個新的全球參考資料,這可能是阻止GC從中解放出來的唯一因素。

給出一個頭文件:

void setData(void *); 
void *getData(); 

和實施:

#include "test.hh" 

namespace { 
    void *d = nullptr; 
} 

void setData(void *d) { 
    ::d = d; 
} 

void *getData() { 
    return d; 
} 

足以讓:

public class run { 
    public static void main(String[] argv) { 
    System.loadLibrary("test"); 
    Object example = "HELLO"; 
    test.setData(example); 
    System.out.println(test.getData()); 
    } 
} 

才能正常工作。

正如所寫,這些類型圖非常難看 - 它們會影響全部的使用void *。所以如果你真的使用過這個,你會想第二次使用%apply%clear來限制它們的影響。您也可以在頭文件中命名參數並使用該參數來限制類型映射的應用位置。

+0

我想我們還需要以某種方式建立一個全球參考,如果我們希望這實際上是一些有用的工作? – 2014-10-01 04:33:12

+0

@SamuelAudet只要'SetUserData'健全就可以工作。 – Flexo 2014-10-01 10:44:24

+0

@SamuelAudet意識到你在得到什麼,他們沒有辦法讓'env',所以我補充了缺少的細節。 – Flexo 2014-10-01 12:21:02

-1

爲了完整起見,下面是另一個(更簡單?)的方式來做到這一點與JavaCPP。假設我們有一個GlobalData.h文件中像這樣在C++:

class Data { 
public: 
    JNIEnv* env; 
    jobject data; 

    Data(JNIEnv* env, jobject obj) : env(env), data(NULL) { } 
    ~Data() { if (data != NULL) env->DeleteGlobalRef(data); } 

    void SetUserData(jobject obj) { 
     if (data != NULL) env->DeleteGlobalRef(data); 
     data = env->NewGlobalRef(obj); 
    } 
    jobject GetUserData() { return data; } 
}; 

我們可以利用它從Java這樣:

import org.bytedeco.javacpp.*; 
import org.bytedeco.javacpp.annotation.*; 

@Platform(include="GlobalData.h") 
public class GlobalData { 
    static { Loader.load(); } 

    public static class Data extends Pointer { 
     public Data() { allocate(); } 
     private native @Raw(withEnv=true) void allocate(); 

     public native void SetUserData(@Raw Object obj); 
     public native @Raw Object GetUserData(); 
    } 

    public static void main(String[] args) { 
     Object someObject = new Object(); 
     Data myData = new Data(); 
     myData.SetUserData(someObject); 
     Object sameObject = myData.GetUserData(); 

     System.out.println(someObject); 
     System.out.println(sameObject); 
    } 
} 

當輸出顯示someObjectsameObject指向同一個對象,例如:

[email protected] 
[email protected]