Mon code commence en Java, appelle C++, qui appelle ensuite Java à nouveau pour des choses comme la recherche, l'obtention et le réglage valeurs de champ.
Dans le cas où une personne à la recherche d'une approche C++ trouve cette page, je laboure avec ceci:
Ce que je suis en train de faire est emballer mes corps de méthode JNI avec un C++ bloc try/catch,
JNIEXPORT void JNICALL Java_com_pany_jni_JNIClass_something(JNIEnv* env, jobject self)
{
try
{
... do JNI stuff
// return something; if not void.
}
catch (PendingException e) // (Should be &e perhaps?)
{
/* any necessary clean-up */
}
}
où PendingException est déclaré trivialement:
class PendingException {};
et j'invoque la méthode suivante après avoir invoqué une JNI de C++, donc si l'état d'exception Java indiquent est une erreur, je vais immédiatement en liberté sous caution et laisser la gestion des exceptions normale Java ajouter la (méthode native) ligne à la trace de la pile, tout en donnant le C++ la possibilité de nettoyer tout déroulage:
PendingException PENDING_JNI_EXCEPTION;
void throwIfPendingException(JNIEnv* env)
{
if (env->ExceptionCheck()) {
throw PENDING_JNI_EXCEPTION;
}
}
Ma pile Java trace ressemble à ceci pour un échec env-> GetFieldId() appel:
java.lang.NoSuchFieldError: no field with name='opaque' signature='J' in class Lcom/pany/jni/JniClass;
at com.pany.jni.JniClass.construct(Native Method)
at com.pany.jni.JniClass.doThing(JniClass.java:169)
at com.pany.jni.JniClass.access$1(JniClass.java:151)
at com.pany.jni.JniClass$2.onClick(JniClass.java:129)
at android.view.View.performClick(View.java:4084)
et assez similaire si j'appelle à une méthode Java qui lance:
java.lang.RuntimeException: YouSuck
at com.pany.jni.JniClass.fail(JniClass.java:35)
at com.pany.jni.JniClass.getVersion(Native Method)
at com.pany.jni.JniClass.doThing(JniClass.java:172)
Je ne peux pas parler à l'emballage l'exception Java au sein d'une autre exception Java au sein de C++, ce qui, je pense, fait partie de votre question - je n'ai pas trouvé le besoin de le faire - mais si je le faisais, je le ferais avec un wrapper Java autour du méthodes natives ou étendent juste mes exceptions jetant des méthodes pour prendre un jthrowable et remplacer le env-> ThrowNew() appeler avec quelque chose de laid: il est malheureux Sun n'a pas fourni une version de ThrowNew qui a pris un jthrowable.
void impendNewJniException(JNIEnv* env, const char *classNameNotSignature, const char *message)
{
jclass jClass = env->FindClass(classNameNotSignature);
throwIfPendingException(env);
env->ThrowNew(jClass, message);
}
void throwNewJniException(JNIEnv* env, const char* classNameNotSignature, const char* message)
{
impendNewJniException(env, classNameNotSignature, message);
throwIfPendingException(env);
}
Je ne considère pas la mise en cache (exception) références constructeur de classe parce que les exceptions ne sont pas censés être un mécanisme de contrôle de flux d'habitude, il devrait donc pas d'importance si elles sont lentes. J'imagine que la recherche n'est pas terriblement lente de toute façon, puisque Java fait probablement sa propre mise en cache pour ce genre de chose.
Par «exceptions enchaînées de poignées», voulez-vous dire que votre code remarquerait une exception au niveau Java lors du retour de Java vers C++, l'encapsulerait dans une autre exception et relèverait cette nouvelle exception de C++ vers Java? –