in subversion/bindings/javahl/native/JNIUtil.cpp [578:715]
jthrowable JNIUtil::wrappedCreateClientException(svn_error_t *err, jthrowable jcause)
{
jstring jmessage;
jobject jstack;
std::string msg = makeSVNErrorMessage(err, &jmessage, &jstack);
if (JNIUtil::isJavaExceptionThrown())
return NULL;
std::string source;
#ifdef SVN_DEBUG
#ifndef SVN_ERR__TRACING
if (err->file)
{
source = err->file;
if (err->line > 0)
{
source += ':';
source += err->line;
}
}
#endif
#endif
if (!jcause)
jcause = JNIUtil::unwrapJavaException(err);
// Much of the following is stolen from throwNativeException(). As much as
// we'd like to call that function, we need to do some manual stack
// unrolling, so it isn't feasible.
JNIEnv *env = getEnv();
// Create a local frame for our references
env->PushLocalFrame(LOCAL_FRAME_SIZE);
if (JNIUtil::isJavaExceptionThrown())
return NULL;
jclass clazz = env->FindClass(JAVAHL_CLASS("/ClientException"));
if (isJavaExceptionThrown())
POP_AND_RETURN_NULL;
if (getLogLevel() >= exceptionLog)
{
JNICriticalSection cs(*g_logMutex);
g_logStream << "Subversion JavaHL exception thrown, message:<";
g_logStream << msg << ">";
if (!source.empty())
g_logStream << " source:<" << source << ">";
if (err->apr_err != -1)
g_logStream << " apr-err:<" << err->apr_err << ">";
g_logStream << std::endl;
}
if (isJavaExceptionThrown())
POP_AND_RETURN_NULL;
jstring jsource = (source.empty() ? NULL : makeJString(source.c_str()));
if (isJavaExceptionThrown())
POP_AND_RETURN_NULL;
jmethodID mid = env->GetMethodID(clazz, "<init>",
"(Ljava/lang/String;"
"Ljava/lang/Throwable;"
"Ljava/lang/String;I"
"Ljava/util/List;)V");
if (isJavaExceptionThrown())
POP_AND_RETURN_NULL;
jobject nativeException = env->NewObject(clazz, mid, jmessage, jcause,
jsource, jint(err->apr_err),
jstack);
if (isJavaExceptionThrown())
POP_AND_RETURN_NULL;
#ifdef SVN_ERR__TRACING
// Add all the C error stack trace information to the Java Exception
// Get the standard stack trace, and vectorize it using the Array class.
static jmethodID mid_gst = 0;
if (mid_gst == 0)
{
mid_gst = env->GetMethodID(clazz, "getStackTrace",
"()[Ljava/lang/StackTraceElement;");
if (isJavaExceptionThrown())
POP_AND_RETURN_NULL;
}
Array stackTraceArray((jobjectArray) env->CallObjectMethod(nativeException,
mid_gst));
std::vector<jobject> oldStackTrace = stackTraceArray.vector();
// Build the new stack trace elements from the chained errors.
std::vector<jobject> newStackTrace;
putErrorsInTrace(err, newStackTrace);
// Join the new elements with the old ones
for (std::vector<jobject>::const_iterator it = oldStackTrace.begin();
it < oldStackTrace.end(); ++it)
{
newStackTrace.push_back(*it);
}
jclass stClazz = env->FindClass("java/lang/StackTraceElement");
if (isJavaExceptionThrown())
POP_AND_RETURN_NULL;
const jsize stSize = static_cast<jsize>(newStackTrace.size());
if (stSize < 0 || stSize != newStackTrace.size())
{
env->ThrowNew(env->FindClass("java.lang.ArithmeticException"),
"Overflow converting C size_t to JNI jsize");
POP_AND_RETURN_NULL;
}
jobjectArray jStackTrace = env->NewObjectArray(stSize, stClazz, NULL);
if (isJavaExceptionThrown())
POP_AND_RETURN_NULL;
int i = 0;
for (std::vector<jobject>::const_iterator it = newStackTrace.begin();
it < newStackTrace.end(); ++it)
{
env->SetObjectArrayElement(jStackTrace, i, *it);
++i;
}
// And put the entire trace back into the exception
static jmethodID mid_sst = 0;
if (mid_sst == 0)
{
mid_sst = env->GetMethodID(clazz, "setStackTrace",
"([Ljava/lang/StackTraceElement;)V");
if (isJavaExceptionThrown())
POP_AND_RETURN_NULL;
}
env->CallVoidMethod(nativeException, mid_sst, jStackTrace);
if (isJavaExceptionThrown())
POP_AND_RETURN_NULL;
#endif
return static_cast<jthrowable>(env->PopLocalFrame(nativeException));
}