2017-02-22 15 views
1

У меня есть класс C++ с виртуальным методом. Я использую режиссеры, и я подклассифицировал класс C++ на Java. Этот класс предназначен для приема обратных вызовов из кода C++. Таким образом, класс Java затем передается методам на C++ и C++ (upcalls to Java). Есть аргументы массива (или массивы указателей, я пробовал оба), и они преобразуются в SWIGTYPE_p_double.Передача массивов из C++ в Java с использованием команд Swig, вызов up

Я хотел бы иметь сигнатуру типа со стороны Java double [] и, конечно, иметь содержимое массива в этом аргументе double [] (копирование содержимого в порядке).

Как я могу это сделать?

Я пытался сделать это с помощью следующего кода, который я поднял из некоторых списков рассылки:

c_backend.i:

%module(directors="1") c_backend 

%{ 
#include "c_backend.h" 
%} 

%typemap(directorin, descriptor="[D") (double *DOUBLE, size_t LENGTH) { 
    jdoubleArray jd = (jenv)->NewDoubleArray($2); 
    (jenv)->SetDoubleArrayRegion(jd, 0, $2, (jdouble *)$1); 
    $input = jd; 
} 
%typemap(directorargout) (double *DOUBLE, size_t LENGTH) 
%{(jenv)->GetDoubleArrayRegion($input, 0, $2, (jdouble *)$1); %} 

%feature("director") CallbackHandler; 

%include "c_backend.h" 

c_backend.h:

#ifndef CALLBACK_HANDLER_H 
#define CALLBACK_HANDLER_H 

#include <stdio.h> 


class CallbackHandler { 
    public: 
    virtual ~CallbackHandler() {} 
    virtual void statusUpdate(double *params, size_t size) { 
     printf("in C++ statusUpdate\n"); 
    } 
}; 


class Server { 
    public: 
    void doSomething(CallbackHandler *); 
}; 

#endif 

c_backend.cpp :

#include "c_backend.h" 

#include <stdio.h> 
#include <stdlib.h> 

void Server::doSomething(CallbackHandler *ch) { 
    double *params = (double *)malloc(3*sizeof(double)); 
    params[0] = 1.1; 
    params[1] = 2.2; 
    params[2] = 3.3; 
    printf("In doSomthing\n"); 
    ch->statusUpdate(params,3); 
    printf("exiting doSomthing\n"); 
} 

JavaFrontend.java:

public class JavaFrontend { 
    static { 
     System.loadLibrary("CBackend"); 
    } 
    public static void main(String[] args) { 
     JFCallbackHandler jf = new JFCallbackHandler(); 
     new Server().doSomething(jf); 
    } 

    public static class JFCallbackHandler extends CallbackHandler { 
     public void statusUpdate(double params[], long size) { 
      System.out.println("Java got params: "+params); 
     } 
    } 
} 

И Makefile для компиляции:

JAVA_INCLUDE=-I/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/include/darwin 

all: 
    c++ -c c_backend.cpp 
    swig -java -c++ $(JAVA_INCLUDE) c_backend.i 
    c++ $(JAVA_INCLUDE) -c c_backend_wrap.cxx 
    c++ -dynamiclib -o libCBackend.jnilib *.o -framework JavaVM 
    javac *.java 

clean: 
    rm -rf *.class *.o *_wrap.cxx *_wrap.h Server.java SWIGTYPE*.java c_backend*.java CallbackHandler.java 

Swig -версия:

SWIG версии 3.0.8

Собран с лязгом ++ [x86_64- apple-darwin15.2.0]

Конфигурация Варианты: изд + PCRE

Пожалуйста, смотрите http://www.swig.org для отчетности ошибок и далее информация

ответ

0

Я получил эту работу с небольшим усилием. Примеры, которые вы нашли в качестве отправной точки, являются разумными, но я думаю, что они не завершены. Я не думаю, что вы можете реально писать директивные директивные/директивные типы, не имея сопоставления в/jtype/jstype/jni/javadirectorin/javain, потому что вы очень быстро заканчиваете несоответствие ожиданий между различными фрагментами сгенерированного кода. (Код директора также может вызывать обычный Java-класс, а также вызываться им).

Также я считаю, что гораздо лучше использовать карту данных с несколькими картами, чтобы скомпоновать аргументы указателя и размера до одного аргумента внутри Java, учитывая, что длина является неявным атрибутом массива в Java.

Так вот краткий обзор того, что я должен был сделать, чтобы заставить его работать:

  1. Во-первых, существующие typemaps не будут применяться к коду, потому что они совпадают на обоих типов arugment и arugment имя. %apply - это аккуратный способ сделать это, особенно для многопараметрических типов, подобных этим.
  2. Во-вторых, добавлены соответствующие типы символов для, а не только для директора.
  3. Вторым образом добавлены typemaps для пропуска double[] на всем пути от C++ к Java через прокси.
  4. И наконец, поскольку тип теперь равен double[] и неявный размер, необходимый для обновления, чтобы он оставался переопределяющим, а не перегрузкой. Для хорошей меры я добавил @Override.

И некоторые стилистические изменения, которые я сделал, потому что они лучше код:

  1. Сняли слепки из входов TypeMap в jdobule. В лучшем случае они должны быть no-op (double* ->jdouble*), но в худшем случае они собираются скрыть что-то неприятное.
  2. Установите типовые формы, чтобы они находились в пределах собственного блока. Это означает, что вы можете использовать одну и ту же типовую карту дважды для одной и той же функции, не сталкиваясь с именами локальных переменных. (Хотя в любом случае я удалял локальную переменную)
  3. Используемые макросы SWIG's JCALLx - это, очевидно, код на C++, но это привычка, которую я стараюсь хранить при написании кода SWIG.

Таким образом, в конце концов ваш интерфейс SWIG выглядел следующим образом:

%module(directors="1") c_backend 

%{ 
#include "c_backend.h" 
%} 

%typemap(jstype) (double *DOUBLE, size_t LENGTH) "double[]" 
%typemap(jtype) (double *DOUBLE, size_t LENGTH) "double[]" 
%typemap(jni) (double *DOUBLE, size_t LENGTH) "jdoubleArray" 
%typemap(javadirectorin) (double *DOUBLE, size_t LENGTH) "$jniinput" 
%typemap(javain) (double *DOUBLE, size_t LENGTH) "$javainput" 
%typemap(in,numinputs=1) (double *DOUBLE, size_t LENGTH) { 
    // Note the NULL here if you don't want to be making changes visible 
    $1 = JCALL2(GetDoubleArrayElements, jenv, $input, NULL); 
    $2 = JCALL1(GetArrayLength, jenv, $input); 
} 
%typemap(freearg) (double *DOUBLE, size_t LENGTH) { 
    // Swap 0 for JNI_ABORT if you don't want to make changes visible 
    JCALL3(ReleaseDoubleArrayElements, jenv, $input, $1, 0); 
} 
%typemap(directorin,descriptor="[D") (double *DOUBLE, size_t LENGTH) { 
    $input = JCALL1(NewDoubleArray, jenv, $2); 
    JCALL4(SetDoubleArrayRegion, jenv, $input, 0, $2, $1); 
} 
%typemap(directorargout) (double *DOUBLE, size_t LENGTH) { 
    (jenv)->GetDoubleArrayRegion($input, 0, $2, $1); 
} 

%feature("director") CallbackHandler; 

%apply (double *DOUBLE, size_t LENGTH) { (double *params, size_t size) }; 

%include "c_backend.h" 

Что было достаточно, чтобы сделать ваш случай работу теста правильно с вышеупомянутыми изменениями, чтобы сделать его переопределение вместо перегрузки в настоящее время.