JNI wrapper for C function using SWIG - what should be the typemap?(使用 SWIG 的 C 函数的 JNI 包装器 - 类型映射应该是什么?)
问题描述
I am trying to create the JNI wrapper for the following functions in C:
int err = new_instance(const char* name, instance_t* instance);
name
- input, instance
- output
int err = get_value(const instance_t instance, int *val);
instance
- input, val
- output
where instance_t
is defined as:
typedef void* instance_t;
I am all lost in the SWIG manual for Java, since it doesn't simply support input parameters as the output type. I had no problems whatsoever with the Python wrapper (shown below).
What is the correct way of using typemap in the case of Java?
// instance_t [argout]
%typemap(in, numinputs=0) instance_t* instance (instance_t temp = 0) {
$1 = &temp;
}
%typemap(argout) instance_t *instance {
%append_output(PyLong_FromLongLong((long long)* $1));
}
// instance_t [in]
%typemap(in) instance_t instance {
$1 = (instance_t) PyLong_AsLongLong($input);
}
You can do this using SWIG and Java in several different ways. I've created the following header to illustrate all my examples, based on what you showed in the question:
typedef void* instance_t;
int new_instance(const char* name, instance_t * instance);
int get_value(const instance_t instance, int *val);
Writing some Java in the interface:
We can use the cpointer.i from the SWIG library to give us the functions we need to write a Java overload that calls the default version of new_instance
(which we make private since it becomes an implementation detail).
%module test
%{
#include "test.h"
%}
%include <cpointer.i>
// Have SWIG create a helper class for "pointer to pointer" type of handle
%pointer_class(instance_t, inst_ptr);
// Hide default version of new_instance
%javamethodmodifiers new_instance "private";
// Supply Java version of new_instance now with useful method signature
%pragma(java) modulecode=%{
public static SWIGTYPE_p_void new_instance(String name) {
inst_ptr ptr = new inst_ptr();
final int err = new_instance(name, ptr.cast());
if (0!=err) {
// throw or whatever
}
return ptr.value();
}
%}
%include "test.h"
Note that this example probably leaks as is since ptr.value()
is non-owning by default.
Writing some C in the interface:
In this next example we write an "overload" (but since I assumed you're writing C and not C++ we had to use %rename
to make this work) in C alone, specifically for the SWIG interface. The original version of the function gets ignored completely since it's pretty useless to us.
%module test
%{
#include "test.h"
%}
// Hide the default new_instance
%ignore new_instance;
%include "test.h"
// Pretend our wrapper specific "overload" was called new_instance all along
%rename(new_instance) new_instance_overload;
// Don't leak our new instance
%newobject new_instance;
// Declare, define and wrap a special version of new_instance
%inline %{
instance_t new_instance_overload(const char* name) {
instance_t result = NULL;
const int err = new_instance(name, &result);
if (err) {
// See later on/other Q for cross language exception example
}
return result;
}
%}
Using typemaps
We can actually do something very similar to your Python example using Java typemaps, although the process is more convoluted since Java has strong typing and we need to respect that.
This solution is also substantially similar to my older answer on the same underlying issue, with the additional complexity that getting strong typing working in Java (instead of just SWIGTYPE_p_void
) is trickier here when the underlying typedef is to void*
instead of a forward declaration of a struct.
%module test
%{
#include "test.h"
%}
// Provide 'instance' class for strong typing (instead of void* semantics)
%rename(Instance) instance;
%nodefaultctor;
struct instance {};
typedef instance * instance_t;
// Don't leak (not that we have a destructor yet, but...)
%newobject new_instance;
// Change new_instance to return instance of Instance
%typemap(jstype) int new_instance "$typemap(jstype,instance_t)";
%typemap(jni) int new_instance "$typemap(jni,instance_t)";
%typemap(jtype) int new_instance "$typemap(jtype,instance_t)";
// Hide the instance_t argument and use a temporary instead under the hood
%typemap(in,numinputs=0) instance_t * ($1_basetype tmp) %{
$1 = &tmp;
%}
// After the call copy the result back
%typemap(argout) instance_t * %{
*($1_ltype)&$result = *$1;
%}
// Inside Java construct the proxy with the correct long pointer
%typemap(javaout) int new_instance {
return new $typemap(jstype,int new_instance)($jnicall, $owner);
}
// Some error handling
%javaexception("Exception") new_instance {
$action
if (!result) {
// JNI code to raise exception, untested in this form
jclass clazz = JCALL1(FindClass, jenv, "Exception");
JCALL2(ThrowNew, jenv, clazz, "Failure creating thing");
return $null;
}
}
%include "test.h"
I would encourage you to look at the generated code around the call to new_instance()
to fully understand what these typemaps are doing.
As far as the call to get_value
is concerned the instance_t
gets handled automatically from the interface above and the int*
arg out needs to get handled either similary to the above example, or using a trick with an array containing only one element:
%include <typemaps.i>
%apply int *OUTPUT { int *val };
%include "test.h"
Which you would then call as:
int outarr[] = new int[1];
final int err = test.get_value(instance, outarr);
// outarr[0] then constains the value
Of course you could then take that trick and use something like the %pragma(java) modulecode
of my first example in this answer to supply another overload that behaves more naturally:
%javamethodmodifiers get_value "private";
%pragma(java) modulecode=%{
public static int get_value(Instance instance) {
int outarr[] = new int[1];
final int err = test.get_value(instance, outarr);
if (0!=err) {
// throw, blah blah
}
return outarr[0];
}
%}
(Note that this trick with arrays would also have worked for a fourth solution to the instance_t*
problem, but because it's not a primitive type there's a lot more work involved for no real gain)
这篇关于使用 SWIG 的 C 函数的 JNI 包装器 - 类型映射应该是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:使用 SWIG 的 C 函数的 JNI 包装器 - 类型映射应该是什么?


- 如何使 JFrame 背景和 JPanel 透明且仅显示图像 2022-01-01
- 在 Java 中,如何将 String 转换为 char 或将 char 转换 2022-01-01
- GC_FOR_ALLOC 是否更“严重"?在调查内存使用情况时? 2022-01-01
- 如何指定 CORS 的响应标头? 2022-01-01
- Eclipse 的最佳 XML 编辑器 2022-01-01
- 未找到/usr/local/lib 中的库 2022-01-01
- 转换 ldap 日期 2022-01-01
- 获取数字的最后一位 2022-01-01
- 将 Java Swing 桌面应用程序国际化的最佳实践是什么? 2022-01-01
- java.lang.IllegalStateException:Bean 名称“类别"的 BindingResult 和普通目标对象都不能用作请求属性 2022-01-01