在最基本的层面上,您可以使用 SWIG 库的 cpointer.i 部分编写代码,以允许在 Java 中创建直接的“指向指针”对象。
例如给定头文件:
#include <stdlib.h>
typedef struct sp_session sp_session;
typedef struct {} sp_session_config;
typedef int sp_error;
inline sp_error sp_session_create(const sp_session_config *config, sp_session **sess) {
// Just for testing, would most likely be internal to the library somewhere
*sess = malloc(1);
(void)config;
return sess != NULL;
}
// Another thing that takes just a pointer
inline void do_something(sp_session *sess) {}
你可以用:
%module spotify
%{
#include "test.h"
%}
%include "test.h"
%include <cpointer.i>
%pointer_functions(sp_session *, SessionHandle)
这让我们可以编写如下内容:
public class run {
public static void main(String[] argv) {
System.loadLibrary("test");
SWIGTYPE_p_p_sp_session session = spotify.new_SessionHandle();
spotify.sp_session_create(new sp_session_config(), session);
spotify.do_something(spotify.SessionHandle_value(session));
}
}
在 Java 中。我们使用SessionHandle_value() 来引用双指针,使用new_SessionHandle() 为我们创建一个双指针对象。 (还有其他函数用于处理双指针对象)。
上面的代码很有效,而且封装起来非常简单,但对于 Java 程序员来说,这很难“直观”,理想情况下,我们会用看起来更像 Java 的东西来公开整个库。
Java 程序员会期望从创建函数返回新的会话句柄对象,并且会使用异常来指示失败。我们可以让 SWIG 使用一些类型映射和对%exception 的一些谨慎使用来生成该接口,方法是稍微更改接口文件:
%module spotify
%{
#include "test.h"
%}
// 1:
%nodefaultctor sp_session;
%nodefaultdtor sp_session;
struct sp_session {};
// 2:
%typemap(in,numinputs=0) sp_session ** (sp_session *tptr) {
$1 = &tptr;
}
// 3:
%typemap(jstype) sp_error sp_session_create "$typemap(jstype,sp_session*)"
%typemap(jtype) sp_error sp_session_create "$typemap(jtype,sp_session*)"
%typemap(jni) sp_error sp_session_create "$typemap(jni,sp_session*)";
%typemap(javaout) sp_error sp_session_create "$typemap(javaout,sp_session*)";
// 4:
%typemap(out) sp_error sp_session_create ""
%typemap(argout) sp_session ** {
*(sp_session **)&$result = *$1;
}
// 5:
%javaexception("SpotifyException") sp_session_create {
$action
if (!result) {
jclass clazz = JCALL1(FindClass, jenv, "SpotifyException");
JCALL2(ThrowNew, jenv, clazz, "Failure creating session");
return $null;
}
}
%include "test.h"
编号的 cmets 对应于这些点:
- 我们希望
sp_session opaque 类型映射到“不错的”Java 类型,但不允许直接在 Java 中创建/删除该类型。 (如果有一个 sp_session_destroy 函数可以安排它在 Java 对象被销毁时自动调用,如果需要使用 javadestruct 类型映射)。 fake, empty definition combined with %nodefaultctor and %nodefaultdtor 对此进行了安排。
- 对于我们要返回的输入参数,我们需要从 Java 接口中隐藏它(使用
numinputs=0),然后提供一些东西来代替它在接口生成的 C 部分中的位置。李>
- 要返回
sp_session 而不是错误代码,我们需要调整函数返回的类型映射 - 最简单的方法是将它们替换为声明函数时将使用的类型映射就像使用 $typemap 返回一个 sp_session。
- 就输出而言,我们不想在通常会被封送的地方做任何事情,但我们确实希望返回我们用作占位符的指针,用于 2 中的额外输入参数。
-
最后,我们希望将整个调用 sp_session_create 包含在一些代码中,该代码将检查实际返回值并将其映射到指示失败的 Java 异常。为此,我还手动编写了以下异常类:
public class SpotifyException extends Exception {
public SpotifyException(String reason) {
super(reason);
}
}
完成所有这些工作后,我们现在可以在 Java 代码中使用它,如下所示:
public class run {
public static void main(String[] argv) throws SpotifyException {
System.loadLibrary("test");
sp_session handle = spotify.sp_session_create(new sp_session_config());
spotify.do_something(handle);
}
}
这比原来的界面更简单、更直观,但编写界面更简单。我的倾向是使用 advanced renaming feature 使类型名称也“看起来更像 Java”。