您可以通过一些工作克服您喜欢的约束(即不维护弱引用的映射)来执行此操作。事实证明,这比我最初预期的要少。我将首先讨论该解决方案,然后再对我第一次尝试执行此操作的方式进行一些讨论,以致于难以完成。
工作解决方案的高级视图是,我们添加了三件事:
- 通过
%extend
内部人员尝试动态强制转换的某些C ++代码Director*
(即,SWIG总监层次结构的一个基础)。如果存在,它将保存对原始Java类的jobject引用。因此,我们可以简单地返回该jboject,如果强制转换失败,则返回NULL。 - 一些Java代码将返回我们的C ++代码的结果,或者
this
如果不合适的话,将返回它们。然后,我们可以从witihin的javadirectorin类型映射中注入调用,以允许从新代理“升级”到原始对象。 - 琐碎的类型映射形式的另一个技巧是
%extend
自动将JNIEnv对象传递到#1方法中,因为通常无法直接在该方法中访问它,即使它可能会这样暴露。
因此,您的接口文件将变为:
%module(directors="1") c_backend%{#include "c_backend.h"#include <iostream>%}%feature("director") Person;%feature("director") JobPool;// Call our extra Java pre to figure out if this was really a Java object to begin with%typemap(javadirectorin) Person * "$jniinput == 0 ? null : new $*javaclassname($jniinput, false).swigFindRealImpl()"// Pass jenv into our %extend pre%typemap(in,numinputs=0) JNIEnv *jenv "$1 = jenv;"%extend Person { // return the underlying Java object if this is a Director, or null otherwise jobject swigOriginalObject(JNIEnv *jenv) { Swig::Director *dir = dynamic_cast<Swig::Director*>($self); std::cerr << "Dynamic_cast: " << dir << "n"; if (dir) { return dir->swig_get_self(jenv); } return NULL; }}%typemap(javapre) Person %{ // check if the C++ pre finds an object and just return ourselves if it doesn't public Person swigFindRealImpl() { Object o = swigOriginalObject(); return o != null ? ($javaclassname)o : this; }%}%include "c_backend.h"我向stderr发出了一封邮件,以证明它确实有效。
在实际代码中,您可能想要添加一个javaout类型映射,该类型映射也可以反映javadirectorin类型映射的功能。您也可以在宏中整齐地打扮它,因为编写所有代码都是为了避免采用固定的类型名称。
如果我不得不猜测为什么SWIG在默认情况下不会做类似的事情,那几乎可以肯定是因为那将强制使用RTTI,但是它过去一直很流行,会
-fno-rtti“为了提高性能” 而传递到您的编译器中,因此有很多代码库尽量避免假设可以依靠动态转换。
如果您仅关心解决方案,请立即停止阅读。但是这里包含的参考是我最终放弃的原始方法。它开始像这样:
//c_backend.i%module(directors="1") c_backend%{#include "c_backend.h"%}%feature("director") Person;%feature("director") JobPool;%typemap(jtype) Person * "Object"%typemap(jnitype) Person * "jobject"%typemap(javadirectorin) Person * "$jniinput instanceof $*javaclassname ? ($*javaclassname)$jniinput : new $*javaclassname((Long)$jniinput), false)"%typemap(directorin,descriptor="L/java/lang/Object;") Person * { SwigDirector_$1_basetype *dir = dynamic_cast<SwigDirector_$1_basetype*>($1); if (!dir) { jclass cls = JCALL1(FindClass, jenv, "java/lang/Long"); jmid ctor = JCALL3(GetMethodID, jenv, cls, "<init>", "J(V)"); $input = JCALL3(NewObject, jenv, cls, ctor, reinterpret_cast<jlong>($1)); } else { $input = dir->swig_get_self(jenv); }}%include "c_backend.h"后者更改了
Person类型以从包装器代码一直返回
Object/
jobject。我的计划是,它要么是一个实例
Person或者
java.lang.Long,我们会动态地决定基于instanceof的比较构造什么样的。
但是,这样做的问题是jnitype和jtype
tyemaps在使用它们的上下文之间没有区别。因此,任何其他用法
Person(例如,构造函数,函数输入,director
out,director代码的其他位)都需要更改为使用
Long对象而不是
long原始类型。即使通过在变量名上匹配类型映射,它仍然不能避免过度匹配。(尝试一下,并注意c_backendJNI.java中长成为Person的地方)。因此,在要求非常明确地命名类型映射方面,这将是很丑陋的,但仍然与我想要的内容不匹配,因此需要对其他类型映射进行更侵入性的更改。



