Это может быть проще, если вы определили иерархию типов для возвращаемых типов и использовали базовый класс в качестве возвращаемого типа для fetchFromRow
.(Оказывается, что решение не так просто, как я думал, и даже пример в документации ! Этот вопрос также относится к Java + SWIG ).Несмотря на то, что выполнение заданного вами вопроса возможно, я сделал более простой пример, чтобы проиллюстрировать важные моменты.
Пример, с которым я здесь работаю, имеет простой интерфейс, test.h
(как объявления, так иопределения для упрощения):
struct type1 {
type1(int foo) : foo(foo) {}
int foo;
};
struct type2 {
type2(double bar) : bar(bar) {}
double bar;
};
// TYPE3 is int32_t, TYPE4 is const char*
typedef enum { TYPE1, TYPE2, TYPE3, TYPE4 } type_t;
void* fetch(type_t type) {
switch(type) {
case TYPE1:
return new type1(101);
case TYPE2:
return new type2(1.111);
case TYPE3:
return (void*)(-123); // One way of returning int32_t via void*!
case TYPE4:
return (void*)("Hello world"); // Cast because not const void*
default:
return NULL;
}
}
Здесь у нас есть четыре различных типа в сочетании со значением enum
.Они были выбраны для простоты.Они могут быть чем угодно, если у вас есть подходящая карта типов, которую можно применить.(Если вы хотите sockaddr_in
конкретно, тогда примените карту типов из моего ответа на ваш предыдущий вопрос о переносе sockaddr_in
конкретно).
Также есть функция fetch
, которая создает одну изтипы и возвращает его через void *
.Это иллюстрирует то, что вы спросили в вопросе.Хитрость с fetch
заключается в том, что SWIG не имеет прямого способа вывести то, что находилось за указателем void*
до того, как он был возвращен.Нам нужно дать SWIG способ более точно узнать, что это за тип, используя наши знания более высокого уровня о значении параметра type_t
.
Чтобы обернуть это, нам нужен файл интерфейса SWIG, test.i
который начинается с обычного модуля:
%module test
%{
#include "test.h"
%}
Чтобы обернуть нашу функцию fetch
, нам нужно найти разумный способ выставить ближайшую вещь к void*
на стороне Java.В этом случае я думаю, что java.lang.Object
является хорошим выбором для возвращаемого типа, и он достаточно хорошо приближается к void*
.
%typemap(jstype) void* "java.lang.Object"
Это устанавливает, какой тип возврата из fetch
на Javaсторона будет.(Мы не изменили тип возвращаемого значения сгенерированного JNI-посредника, используя %typemap(jtype)
, однако по умолчанию он будет long
, как и раньше).
Далее нам нужно написать еще одну карту типов, чтобы указать, как результатфактического вызова будет преобразован в тип, который мы сказали, что вызов вернется на стороне Java:
%typemap(javaout) void* {
long cPtr = $jnicall;
Object result = null;
if (type == type_t.TYPE1) {
result = new type1(cPtr, $owner);
}
else if (type == type_t.TYPE2) {
result = new type2(cPtr, $owner);
}
else if (type == type_t.TYPE3) {
result = void2int(cPtr);
// could also write "result = new Integer(void2int(cPtr));" explicitly here
}
else if (type == type_t.TYPE4) {
result = void2str(cPtr);
}
return result;
}
%newobject fetch(type_t type);
Здесь мы создаем объект Java, соответствующие прокси-типы SWIG, или вызываемвспомогательную функцию мы увидим в ближайшее время.Мы решаем, какой тип печатать, используя type_t
, который использовался при вызове.(Я не на 100% доволен ссылкой на этот тип по имени, то есть type
напрямую, но, похоже, нет лучшего способа получить доступ к параметрам, с которыми функция вызывается внутри javaout
карты типов)
Второй аргумент для каждого из конструкторов, рассматриваемый здесь как $owner
, важен для управления памятью, в нем указывается, кому принадлежит распределение, и мы хотели бы перенести владение на Java, чтобы избежать его утечки.Его значение определяется директивой %newobject
.
Нам нужна вспомогательная функция для преобразования void*
в более значимые типы для случаев int32_t
и String
.Мы поставляем это с %inline
, чтобы попросить SWIG обернуть и определить его одновременно:
%inline %{
int32_t void2int(jlong v) {
return (intptr_t)v;
}
const char *void2str(jlong v) {
return (const char*)v;
}
%}
Я использовал jlong
здесь, потому что на стороне Java интерфейса все указатели представлены как long
.Это гарантирует, что функции точно совместимы с тем, что возвращает вызов JNI, без потери точности (на некоторых платформах возможно, что jlong
может быть long long
).В основном эти функции существуют для того, чтобы сделать преобразование из общего (void*
) в специфическое на стороне C с минимальным ручным трудом, насколько это возможно.SWIG обрабатывает все типы для нас здесь.
Наконец мы заканчиваем с %include
для заголовочного файла (мы хотим обернуть все это так, чтобы это было проще всего) и некоторый код, чтобы библиотека получилазагружен автоматически:
%include "test.h"
%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary("test");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. \n" + e);
System.exit(1);
}
}
%}
Я проверил эту упаковку, скомпилировав:
swig -Wall -java -c++ test.i
javac *.java
g++ -Wall -Wextra test_wrap.cxx -shared -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux/ -o libtest.so
и выполнив следующий Java-код, чтобы немного его «тренировать».
public class main {
public static void main(String[] argv) {
Object o1 = test.fetch(type_t.TYPE1);
Object o2 = test.fetch(type_t.TYPE2);
Object o3 = test.fetch(type_t.TYPE3);
Object o4 = test.fetch(type_t.TYPE4);
if (!(o1 instanceof type1)) {
System.out.println("Wrong type - o1");
}
else {
System.out.println("o1.getFoo(): " + ((type1)o1).getFoo());
}
if (!(o2 instanceof type2)) {
System.out.println("Wrong type - o2");
}
else {
System.out.println("o2.getFoo(): " + ((type2)o2).getBar());
}
if (!(o3 instanceof Integer)) {
System.out.println("Wrong type - o3");
}
else {
System.out.println("o3.intValue(): " + ((Integer)o3).intValue());
}
if (!(o4 instanceof String)) {
System.out.println("Wrong type - o4");
}
else {
System.out.println("o4: " + (String)o4);
}
}
}
Вы всегда можете воссоздать весь пример из кода, показанного здесь, test.i
показывается и обсуждается последовательно, но для удобства я также разместил копию test.i на моем сайте .