首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在JNI代码中抛出异常的最好方法?

在JNI代码中抛出异常的最好方法?
EN

Stack Overflow用户
提问于 2008-10-23 17:43:41
回答 4查看 41.4K关注 0票数 64

我希望有一种一致且简单的方法来在JNI代码中抛出异常;这种方法可以处理链式异常(隐式地从env->ExceptionOccurred方法,或者显式地通过参数,这两种方式都是好的),并且每次我想这样做时都不用去查找构造函数。尽管我可以在需要时将其从C++翻译过来,但以上所有内容最好是用C语言编写的。

SO上的任何人都有这样的东西可以分享吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2008-10-27 16:29:01

我们只是为我们想要抛出的每种异常类型编写实用程序方法。下面是一些示例:

代码语言:javascript
复制
jint throwNoClassDefError( JNIEnv *env, char *message )
{
    jclass exClass;
    char *className = "java/lang/NoClassDefFoundError";

    exClass = (*env)->FindClass( env, className);
    if (exClass == NULL) {
        return throwNoClassDefError( env, className );
    }

    return (*env)->ThrowNew( env, exClass, message );
}

jint throwNoSuchMethodError(
        JNIEnv *env, char *className, char *methodName, char *signature )
{

    jclass exClass;
    char *exClassName = "java/lang/NoSuchMethodError" ;
    LPTSTR msgBuf;
    jint retCode;
    size_t nMallocSize;

    exClass = (*env)->FindClass( env, exClassName );
    if ( exClass == NULL ) {
        return throwNoClassDefError( env, exClassName );
    }

    nMallocSize = strlen(className) 
            + strlen(methodName)
            + strlen(signature) + 8;

    msgBuf = malloc( nMallocSize );
    if ( msgBuf == NULL ) {
        return throwOutOfMemoryError
                ( env, "throwNoSuchMethodError: allocating msgBuf" );
    }
    memset( msgBuf, 0, nMallocSize );

    strcpy( msgBuf, className );
    strcat( msgBuf, "." );
    strcat( msgBuf, methodName );
    strcat( msgBuf, "." );
    strcat( msgBuf, signature );

    retCode = (*env)->ThrowNew( env, exClass, msgBuf );
    free ( msgBuf );
    return retCode;
}

jint throwNoSuchFieldError( JNIEnv *env, char *message )
{
    jclass exClass;
    char *className = "java/lang/NoSuchFieldError" ;

    exClass = (*env)->FindClass( env, className );
    if ( exClass == NULL ) {
        return throwNoClassDefError( env, className );
    }

    return (*env)->ThrowNew( env, exClass, message );
}

jint throwOutOfMemoryError( JNIEnv *env, char *message )
{
    jclass exClass;
    char *className = "java/lang/OutOfMemoryError" ;

    exClass = (*env)->FindClass( env, className );
    if ( exClass == NULL ) {
        return throwNoClassDefError( env, className );
    }

    return (*env)->ThrowNew( env, exClass, message );
}

这样就很容易找到它们,您的代码完成编辑器将帮助您键入它们,并且您可以传递简单的参数。

我相信你可以扩展它来处理链式异常,或者其他更复杂的方法。这足以满足我们的需求。

票数 54
EN

Stack Overflow用户

发布于 2012-03-22 05:01:23

我只用了两行:

代码语言:javascript
复制
 sprintf(exBuffer, "NE%4.4X: Caller can %s %s print", marker, "log", "or");
 (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/Exception"), exBuffer);

产生:

代码语言:javascript
复制
 Exception in thread "main" java.lang.Exception: NE0042: Caller can log or print.
票数 27
EN

Stack Overflow用户

发布于 2012-08-31 20:56:22

我的代码从Java语言开始,调用C++,然后它再次调用Java语言来查找、获取和设置字段值。

如果使用C++方法的人发现了这个页面,我将继续这样做:

我现在所做的是用JNI /catch块包装我的C++方法体,

代码语言:javascript
复制
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 */
    }
}

其中简单地声明了PendingException:

代码语言:javascript
复制
class PendingException {};

在从C++调用任何JNI之后,我将调用以下方法,因此,如果Java异常状态指示错误,我将立即退出,并让正常的Java异常处理将(本机方法)行添加到堆栈跟踪中,同时让C++有机会在展开时进行清理:

代码语言:javascript
复制
PendingException PENDING_JNI_EXCEPTION;
void throwIfPendingException(JNIEnv* env)
{
    if (env->ExceptionCheck()) {
        throw PENDING_JNI_EXCEPTION;
    }
}

对于失败的env->GetFieldId()调用,我的Java堆栈跟踪如下所示:

代码语言:javascript
复制
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)

如果我调用一个Java方法,它抛出:

代码语言:javascript
复制
 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)

我不能谈论从C++内部将Java异常包装在另一个Java异常中,我认为这是您问题的一部分--我还没有发现需要这样做--但是如果我这样做了,我要么用一个围绕本机方法的Java级包装器来做,要么只是扩展我的异常抛出方法来接受jthrowable,并用丑陋的东西替换env-> ThrowNew ()调用:不幸的是,Sun没有提供一个接受jthrowable的ThrowNew版本。

代码语言:javascript
复制
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);
}

我不会考虑缓存(异常)类构造函数引用,因为异常不应该是一种常见的控制流机制,所以即使它们很慢也没关系。我想不管怎样,查找并不是特别慢,因为Java可能会为这类事情做自己的缓存。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/230689

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档