JNI 코드에서 예외를 발생시키는 가장 좋은 방법은 무엇입니까?
JNI 코드에서 예외를 발생시키는 일관되고 간단한 방법을 원합니다. 체인 된 예외를 처리하고 (env-> ExceptionOccurred 메서드에서 암시 적으로 또는 매개 변수에 의해 명시 적으로 지정하는 것이 좋습니다.)이 작업을 수행 할 때마다 생성자를 찾는 데 도움이됩니다. 필요한 경우 C ++에서 번역 할 수 있지만 위의 모든 내용은 바람직하게는 C로되어 있습니다.
그래서 누구든지 공유 할 수있는 이와 같은 것을 가지고 있습니까?
우리는 던지기를 원하는 각 예외 유형에 대한 유틸리티 메서드를 코딩합니다. 여기 예시들이 있습니다 :
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 );
}
이렇게하면 쉽게 찾을 수 있고 코드 완성 편집기에서 입력하는 데 도움이되고 간단한 매개 변수를 전달할 수 있습니다.
이 기능을 확장하여 연결된 예외 또는 기타 더 복잡한 접근 방식을 처리 할 수 있다고 확신합니다. 이것은 우리의 필요를 충족시키기에 충분했습니다.
I simply use 2 lines:
sprintf(exBuffer, "NE%4.4X: Caller can %s %s print", marker, "log", "or");
(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/Exception"), exBuffer);
Produces:
Exception in thread "main" java.lang.Exception: NE0042: Caller can log or print.
My code starts in Java, invokes C++, which then invokes Java back again for things like finding, getting, and setting field values.
In case someone looking for a C++ approach finds this page, I'll plough on with this:
What I'm now doing is wrapping my JNI method bodies up with a C++ try/catch block,
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 */
}
}
where PendingException is declared trivially:
class PendingException {};
and I'm invoking the following method after invoking any JNI from C++, so if the Java exception status indicates an error, I'll bail immediately and let the normal Java exception handling add the (Native method) line to the stack trace, while giving the C++ the opportunity to clean up while unwinding:
PendingException PENDING_JNI_EXCEPTION;
void throwIfPendingException(JNIEnv* env)
{
if (env->ExceptionCheck()) {
throw PENDING_JNI_EXCEPTION;
}
}
My Java stack trace looks like this for a failed env->GetFieldId() call:
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)
and pretty similar if I call up to a Java method that throws:
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)
I can't talk to wrapping the Java exception within another Java exception from within C++, which I think is part of your question - I've not found the need to do that - but if I did, I'd either do it with a Java-level wrapper around the native methods, or just extend my exception-throwing methods to take a jthrowable and replace the env->ThrowNew() call with something ugly: it's unfortunate Sun didn't provide a version of ThrowNew that took a 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);
}
I wouldn't consider caching (exception) class constructor references because exceptions aren't supposed to be a usual control flow mechanism, so it shouldn't matter if they're slow. I imagine look-up isn't terribly slow anyway, since Java presumably does its own caching for that sort of thing.
I will put a more complete and general answer for who need a little bit more explanations like I need before.
First is nice to set your method with a Throw Exception
so the IDE will ask for try/catch.
public native int func(Param1, Param2, Param3) throws IOException;
I decide for IOException
over Exception
because of this.
JNIEXPORT int JNICALL Java_YourClass_func
(int Param1, int Param2, int Param3) {
if (Param3 == 0) { //something wrong
jclass Exception = env->FindClass("java/lang/Exception");
env->ThrowNew(Exception, "Can't divide by zero."); // Error Message
}
return (Param1+Param2)/Param3;
}
ReferenceURL : https://stackoverflow.com/questions/230689/best-way-to-throw-exceptions-in-jni-code
'programing' 카테고리의 다른 글
LINUX C에서 stdout과 STDOUT_FILENO의 차이점 (0) | 2021.01.08 |
---|---|
package.json에서 'files'및 'directories'속성을 어떻게 사용합니까? (0) | 2021.01.08 |
공용 속성 및 개인 필드를 사용해야합니까 아니면 데이터에 공용 필드를 사용해야합니까? (0) | 2021.01.08 |
return 문이 없을 때 javascript 함수는 무엇을 반환합니까? (0) | 2021.01.08 |
분리 된 대 결합 가능한 POSIX 스레드 (0) | 2021.01.08 |