/* * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #ifndef __CallHelper_hpp__ #define __CallHelper_hpp__ #include #include #include #undef NDEBUG #include #include #include /* * basis of classes to provide a bunch of checking in native calls to java */ class CallHelper { public: CallHelper(JNIEnv* e, const std::string& cname, const std::string& mname, const std::string& sig) : classname(cname), method(mname), signature(sig), m(nullptr), env(e) { c = env->FindClass(classname.c_str()); assert (c != nullptr); } protected: // emit a message with the call made appended to the message void emitErrorMessage(const std::string& msg) { std::string nm = classname; std::replace(nm.begin(), nm.end(), '/', '.'); ::fprintf(stderr, "ERROR: %s::%s, %s\n", nm.c_str(), method.c_str(), msg.c_str()); } // check the given object which is expected to be null void checkReturnNull(jobject obj) { if (obj != nullptr) { emitErrorMessage("Null return expected"); ::exit(-1); } } // check the given object which is expected to NOT be null void checkReturnNotNull(jobject obj) { if (obj == nullptr) { emitErrorMessage("Non-Null return expected"); ::exit(-1); } } // check if any unexpected exceptions were thrown void checkException() { if (env->ExceptionOccurred() != nullptr) { emitErrorMessage("Exception was thrown"); env->ExceptionDescribe(); ::exit(-1); } } // check if an expected exception was thrown void checkExpectedExceptionThrown(const std::string& exception) { jclass expected = env->FindClass(exception.c_str()); assert(expected != nullptr); jthrowable t = env->ExceptionOccurred(); if (env->IsInstanceOf(t, expected) == JNI_FALSE) { emitErrorMessage("Didn't get the expected " + exception); ::exit(-1); } env->ExceptionClear(); } protected: std::string classname; std::string method; std::string signature; jclass c; jmethodID m; JNIEnv* env; }; /* * support for making checked calls on instances of an object */ class InstanceCall : public CallHelper { public: InstanceCall(JNIEnv* e, const std::string& cname, const std::string& mname, const std::string& sig) : CallHelper(e, cname, mname, sig) { m = env->GetMethodID(c, method.c_str(), signature.c_str()); assert(m != nullptr); } // call on the given object, checking for exceptions and that the return is not null jobject callReturnNotNull(jobject obj) { jobject robj = call(obj); checkReturnNotNull(robj); return robj; } // call on the given object with an argument, // checking for exceptions and that the return is not null jobject callReturnNotNull(jobject obj, jobject arg) { jobject robj = call(obj, arg); checkReturnNotNull(robj); return robj; } // call on the given object, checking for exceptions and that the return is null jobject callReturnIsNull(jobject obj) { jobject robj = call(obj); checkReturnNull(robj); return robj; } // call on the given object with an argument, // checking for exceptions and that the return is null jobject callReturnIsNull(jobject obj, jobject arg) { jobject robj = call(obj, arg); checkReturnNull(robj); return robj; } // call a void method checking if exceptions were thrown void callVoidMethod(jobject obj) { env->CallVoidMethod(obj, m); checkException(); } jobject call(jobject obj) { jobject robj = env->CallObjectMethod(obj, m); checkException(); return robj; } jobject call(jobject obj, jobject arg) { jobject robj = env->CallObjectMethod(obj, m, arg); checkException(); return robj; } }; /* * support for making checked static calls */ class StaticCall : public CallHelper { public: StaticCall(JNIEnv* e, const std::string& cname, const std::string& mname, const std::string& sig) : CallHelper(e, cname, mname, sig) { m = env->GetStaticMethodID(c, method.c_str(), signature.c_str()); assert(m != nullptr); } // call a method returning an object checking for exceptions and // the return value is not null. jobject callReturnNotNull(jobject arg) { jobject robj = env->CallStaticObjectMethod(c, m, arg); checkException(); checkReturnNotNull(robj); return robj; } // call a void method checking if any exceptions thrown void callVoidMethod() { env->CallStaticVoidMethod(c, m); checkException(); } // call method returning boolean that is expected to throw the // given exception void callBooleanMethodWithException(const std::string& exception) { env->CallStaticBooleanMethod(c, m); checkExpectedExceptionThrown(exception); } // call method returning an object that is expected to throw the // given exception void callObjectMethodWithException(const std::string& exception) { env->CallStaticObjectMethod(c, m); checkExpectedExceptionThrown(exception); } }; void emitErrorMessageAndExit(const std::string& msg) { ::fprintf(stderr, "ERROR: %s\n", msg.c_str()); ::exit(-1); } #endif // __CallHelper_hpp__