私はのセマンティクスを前提と何のダミー実装を書いて開始するには、しかし、私は「タイプマップ」itemListの変数
Cヘッダファイルの状態で機能することはできませんよ参照した2つの関数は、
です。
これは、私がmy previous answerで与えた答えと組み合わせて、(Javaの開発者の視点では)やっかいではあるが、itemList
のメンバーを働かせるには十分である。
前の回答のタイプマップを正しく使用するには、何を呼び出すべきか(または%apply
のために何を書くべきか)を調べるだけです。 SWIGはこれを把握するのに役立つ便利な方法を持っています。コマンドライン引数-debug-tmsearch
には、何も入力されなかったために考慮され無視されたすべての候補が出力されます。だから私は走った:
swig3.0 -java -Wall -debug-tmsearch test.i
それは私たちが前の答えからのタイプマップとそれをマッチさせる方法を示している。 char *_PROJECTDETAILS::_PROJECTDETAILS_info::itemList
は、私たちが私たちの前のタイプマップを適用したいPROJECTDETAILS::info::itemList
メンバーのための最も厳しい試合であることを示している
test.h:16: Searching for a suitable 'out' typemap for: char *_PROJECTDETAILS::_PROJECTDETAILS_info::itemList
Looking for: char *_PROJECTDETAILS::_PROJECTDETAILS_info::itemList
Looking for: char *itemList
Looking for: char *
Using: %typemap(out) char *
。だから、私たちは(複数の用途にそれらを一致させるために%apply
を使用してもまたは)異なっこの回答や試合の前のタイプマップを使用することができ、何かのように:
%module test
%{
#include "test.h"
#include <assert.h>
%}
// See part 2 for discusson of these
%rename("%(strip:[_])s") "";
%immutable _PROJECTDETAILS::infoType;
%typemap(jni) char * _PROJECTDETAILS::_PROJECTDETAILS_info::itemList "jobjectArray";
%typemap(jtype) char * _PROJECTDETAILS::_PROJECTDETAILS_info::itemList "String[]";
%typemap(jstype) char * _PROJECTDETAILS::_PROJECTDETAILS_info::itemList "String[]";
%typemap(javaout) char * _PROJECTDETAILS::_PROJECTDETAILS_info::itemList {
return $jnicall;
}
%typemap(out) char * _PROJECTDETAILS::_PROJECTDETAILS_info::itemList {
size_t count = 0;
const char *pos = $1;
while (*pos) {
while (*pos++); // SKIP
++count;
}
$result = JCALL3(NewObjectArray, jenv, count, JCALL1(FindClass, jenv, "java/lang/String"), NULL);
pos = $1;
size_t idx = 0;
while (*pos) {
jobject str = JCALL1(NewStringUTF, jenv, pos);
assert(idx<count);
JCALL3(SetObjectArrayElement, jenv, $result, idx++, str);
while (*pos++); // SKIP
}
//free($1); // Iff you need to free the C function's return value
}
%include "test.h"
は、これはそれがあった主な理由は、前の回答から、方法2を選びました完全に型マップに基づいているので、-debug-tmsearch
SWIG引数のより良い例です。我々はとしてそれを使用することができます十分だ
:
import java.util.Arrays;
public class run {
public static void main(String[] argv) {
System.loadLibrary("test");
PROJECT p = test.OpenProject(1,"???");
PROJECTDETAILS pd1 = new PROJECTDETAILS();
test.GetProjectDetails(p, 1, pd1);
System.out.println(Arrays.toString(pd1.getInfo().getItemList()));
}
}
しかし、我々はちょうどGetProjectDetails
に引数として渡すために新しいPROJECTDETAILS
オブジェクトを作成し、Javaのユーザーのためのものよりもはるかに良い行うことができますは少し奇妙です。
あなたは
char *
は珍しいセマンティクスを持つだけのメンバ変数のほかに、やりたいかなりの数のものがあるのJavaにきちんとこれをラップします。
最初に、あなたが持っているいくつかの構造体の名前を変更したいと思います。これは、高度な名前変更ストリップ演算子を使用してSWIG 2.0以降で行うことができます。
次に、メンバー自身をラップする方法を決定する必要があります。 Cの典型的なデザインパターンは、intを使用して、指定されたオブジェクトに対して、どのユニオンのメンバーが正しいタイプであるかを示すことです。 Pythonでは、それぞれのケースで異なるタイプを返し、ダックタイピングに頼っています。
- あなたはクラス階層を定義し、右の型にキャストする方法を見つけ出すために
instanceof
(または単にint型)を使用することができますJavaの場合賢明だろうさまざまなオプションがいくつかあります。
- そのままの状態でCのセマンティクスを反映させることができます。 (「間違った」メンバーに技術的にアクセスすることは未定義の動作ですが、これはJava開発者にとっては直感的ではありません)。
- 「間違った」メンバにアクセスしようとすると、例外を発生させる型を返すか、代わりにNULLを返すことができます。
オプション2は、この回答の以前の部分です。私の考え方では、オプション3はおそらくJavaプログラマにとって最も予測可能な動作なので、ここでやったことがあります。
第3の楽しい決定は、出力関数の引数を処理する方法です。この例では、より多くのJavaコードをC/JNIよりも好むソリューションを選ぶつもりですが、以前の回答と同じトレードオフがここでも適用されます。
私がしたことは、SWIGにPROJECTDETAILS::info
を完全に無視させ、アンダースコアの接頭辞を付けた構造体の名前を変更することです。
次に、ヘッダファイル内のGetProjectDetails
のバージョンをプライベートにし、接尾辞Impl
を追加して、ラッパーの内部以外の誰かがそれに触れることを意図していないことを示しました。
モジュール自体の中に、別の公開バージョンGetProjectDetails
を追加して、新しいオブジェクトが出力専用引数として構成されていることを隠すと、戻り値の型がこれを返すように変更されます。また、 'int
を使用して、' C言語のコーディングスタイルがJavaの '正しくない場合に例外をスローする'ことを示します。 (これを行うよりもSWIGにはもっと多くの方法がありますが、C/JNIの学習曲線を最小限に抑えてそのようにしています)。
次に、ラップされたPROJECTDETAILS
構造体に、2つの追加の読み取り専用メンバー変数を追加します。これらは実際にC言語では直接存在しないので、特別なCコードによって中間インタフェースのグルーコードに実装されています。このコードのポイントは、タイプを示すint
メンバを使用して、実際にunion
がどのケースにあるかをチェックすることです。型が正しくない場合、nullを返します(ただし、CまたはJavaのグルーコードを使用すると例外が発生する可能性があります)。
これで済むのは、以前の回答のtypemapsを再利用して、言語の境界を越えて正しく機能するセマンティクスを取得することだけです。もう一度、ここでメソッド2を使用しました。ヌルを返す関数のマイナーな問題以外は変更されていません。
import java.util.Arrays;
public class run {
public static void main(String[] argv) {
System.loadLibrary("test");
PROJECT p = test.OpenProject(1,"???");
System.out.println("PD1");
PROJECTDETAILS pd1 = test.GetProjectDetails(p, 1);
System.out.println(Arrays.toString(pd1.getItemList()));
System.out.println(pd1.getProjectName());
System.out.println("PD2");
PROJECTDETAILS pd2 = test.GetProjectDetails(p, 2);
System.out.println(Arrays.toString(pd2.getItemList()));
System.out.println(pd2.getProjectName());
}
}
:その後で動作します
%module test
%{
#include "test.h"
#include <assert.h>
%}
%rename("%(strip:[_])s") "";
%immutable _PROJECTDETAILS::infoType;
%ignore info; // Ignore the member
%ignore _PROJECTDETAILS_info; // Ignore the anonymous type
%javamethodmodifiers GetProjectDetails "private";
%rename(GetProjectDetailsImpl) GetProjectDetails;
%typemap(jni) char *_PROJECTDETAILS::itemList "jobjectArray";
%typemap(jtype) char *_PROJECTDETAILS::itemList "String[]";
%typemap(jstype) char *_PROJECTDETAILS::itemList "String[]";
%typemap(javaout) char *_PROJECTDETAILS::itemList {
return $jnicall;
}
%typemap(out) char *_PROJECTDETAILS::itemList {
if (!$1) return NULL; // This fixes a possible bug in my previous answer
size_t count = 0;
const char *pos = $1;
while (*pos) {
while (*pos++); // SKIP
++count;
}
$result = JCALL3(NewObjectArray, jenv, count, JCALL1(FindClass, jenv, "java/lang/String"), NULL);
pos = $1;
size_t idx = 0;
while (*pos) {
jobject str = JCALL1(NewStringUTF, jenv, pos);
assert(idx<count);
JCALL3(SetObjectArrayElement, jenv, $result, idx++, str);
while (*pos++); // SKIP
}
//free($1); // Iff you need to free the C function return value
}
%pragma(java) modulecode=%{
public static PROJECTDETAILS GetProjectDetails(PROJECT p, int a) {
PROJECTDETAILS out = new PROJECTDETAILS();
final int ret = GetProjectDetailsImpl(p,a,out);
if (0!=ret) {
// assuming this is an error throw something
}
return out;
}
%}
%extend _PROJECTDETAILS {
const char *itemList const {
if ($self->infoType != INFOTYPE_ITEMLIST) {
// Throw a Java exception here instead? That is another question...
return NULL;
}
return $self->info.itemList;
}
const char *projectName const {
if ($self->infoType != INFOTYPE_PROJECTNAME) {
// Throw exception?
return NULL;
}
return $self->info.projectName;
}
}
%include "test.h"
:
(注_資本文字が続くで始まるものは、おそらくないあなたのせいではなく、正確に素晴らしいではありませんC reserved nameです)遅い返信のための私の謝罪!私は両方の提案された実装を試して、彼らは完全に動作します! 私は本当にあなたが提供した明確で広範な説明を本当に感謝していると言わなければなりません。実際に何が起きているかをよりよく理解するのに役立ちます(単にコピー&ペーストから私の指を横切り、 – c3po
ヘッダーファイル内の別の関数はPROJECTDETAILS構造体を入力パラメータとして取ります。SWIG生成コードでPROJECTDETAILSのinfoTypeを設定できますが、infoTypeに関連付けられた変数の値を設定することはできません。 projectName。あなたがそれを設定できる '%immutable'を削除した場合、これを推測するには%typemap – c3po
@ c3poを追加する必要がありますが、既存の値を自由にするなど何かをする必要がある場合は、 – Flexo