Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,24 @@ project(jnipp)
find_package(JNI REQUIRED)
include(CTest)

option(
JNIPP_USE_EXCEPTION_HANDLING
"Enable exception handling in JNIPP."
ON
)

add_library(jnipp jnipp.cpp)

if(NOT JNIPP_USE_EXCEPTION_HANDLING)
target_compile_definitions(jnipp PUBLIC JNIPP_USE_EXCEPTION=0)

if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_compile_options(jnipp PRIVATE -fno-exceptions)
endif()
else()
target_compile_definitions(jnipp PUBLIC JNIPP_USE_EXCEPTION=1)
endif()

target_include_directories(
jnipp
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ extern "C" void Java_com_example_Demo_run(jni::JNIEnv* env, jni::jobject obj)

## Configuration

By default, *jnipp* uses std::runtime_error as the base exception class. If you wish,
By default, *jnipp* uses `std::runtime_error` as the base exception class. If you wish,
you can define `JNIPP_EXCEPTION_CLASS` to be the exception class you wish to use, before
including `jnipp.h`. It just needs a `const char*` constructor.

### Disabling exceptions

*jnipp* supports a no-exception mode, in which all `throw` expressions will be replaced with calls to `std::terminate()`. It can be enabled by compiling the library with `JNIPP_USE_EXCEPTION` defined to value `0`. This is also controlled by the CMake option called `JNIPP_USE_EXCEPTION_HANDLING`, which is `ON` by default (i.e. exceptions will by default be *enabled*).
37 changes: 22 additions & 15 deletions jnipp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
// Local Dependencies
#include "jnipp.h"

#if JNIPP_USE_EXCEPTION
#include <exception>
#define JNIPP_THROW(...) do { throw __VA_ARGS__; } while(0)
#else
#define JNIPP_THROW(...) do { std::terminate(); } while(0)
#endif

namespace jni
{
// Static Variables
Expand Down Expand Up @@ -65,7 +72,7 @@ namespace jni
return;

if (vm == nullptr)
throw InitializationException("JNI not initialized");
JNIPP_THROW(InitializationException("JNI not initialized"));

if (!getEnv(vm, &_env))
{
Expand All @@ -74,7 +81,7 @@ namespace jni
#else
if (vm->AttachCurrentThread((void**)&_env, nullptr) != 0)
#endif
throw InitializationException("Could not attach JNI to thread");
JNIPP_THROW(InitializationException("Could not attach JNI to thread"));

_attached = true;
}
Expand Down Expand Up @@ -182,7 +189,7 @@ namespace jni
if (ref == nullptr)
{
env()->ExceptionClear();
throw NameResolutionException(name);
JNIPP_THROW(NameResolutionException(name));
}

return ref;
Expand All @@ -200,7 +207,7 @@ namespace jni

env->ExceptionClear();
std::string msg = obj.call<std::string>("toString");
throw InvocationException(msg.c_str());
JNIPP_THROW(InvocationException(msg.c_str()));
}
}

Expand Down Expand Up @@ -258,7 +265,7 @@ namespace jni
if (isVm.compare_exchange_strong(expected, true))
{
if (javaVm == nullptr && env->GetJavaVM(&javaVm) != 0)
throw InitializationException("Could not acquire Java VM");
JNIPP_THROW(InitializationException("Could not acquire Java VM"));
}
}

Expand Down Expand Up @@ -668,7 +675,7 @@ namespace jni
jfieldID id = env()->GetFieldID(getHandle(), name, signature);

if (id == nullptr)
throw NameResolutionException(name);
JNIPP_THROW(NameResolutionException(name));

return id;
}
Expand All @@ -678,7 +685,7 @@ namespace jni
jfieldID id = env()->GetStaticFieldID(getHandle(), name, signature);

if (id == nullptr)
throw NameResolutionException(name);
JNIPP_THROW(NameResolutionException(name));

return id;
}
Expand All @@ -688,7 +695,7 @@ namespace jni
jmethodID id = env()->GetMethodID(getHandle(), name, signature);

if (id == nullptr)
throw NameResolutionException(name);
JNIPP_THROW(NameResolutionException(name));

return id;
}
Expand All @@ -703,7 +710,7 @@ namespace jni
return getMethod(std::string(nameAndSignature, sig - nameAndSignature).c_str(), sig);

if (id == nullptr)
throw NameResolutionException(nameAndSignature);
JNIPP_THROW(NameResolutionException(nameAndSignature));

return id;
}
Expand All @@ -713,7 +720,7 @@ namespace jni
jmethodID id = env()->GetStaticMethodID(getHandle(), name, signature);

if (id == nullptr)
throw NameResolutionException(name);
JNIPP_THROW(NameResolutionException(name));

return id;
}
Expand All @@ -727,7 +734,7 @@ namespace jni
return getStaticMethod(std::string(nameAndSignature, sig - nameAndSignature).c_str(), sig);

if (id == nullptr)
throw NameResolutionException(nameAndSignature);
JNIPP_THROW(NameResolutionException(nameAndSignature));

return id;
}
Expand Down Expand Up @@ -1445,9 +1452,9 @@ namespace jni
std::string path = path_ ? path_ : detectJvmPath();

if (path.length() == 0)
throw InitializationException("Could not locate Java Virtual Machine");
JNIPP_THROW(InitializationException("Could not locate Java Virtual Machine"));
if (!isVm.compare_exchange_strong(expected, true))
throw InitializationException("Java Virtual Machine already initialized");
JNIPP_THROW(InitializationException("Java Virtual Machine already initialized"));

if (javaVm == nullptr)
{
Expand Down Expand Up @@ -1485,7 +1492,7 @@ namespace jni
if (lib == NULL)
{
isVm.store(false);
throw InitializationException("Could not load JVM library");
JNIPP_THROW(InitializationException("Could not load JVM library"));
}

CreateVm_t JNI_CreateJavaVM = (CreateVm_t) ::dlsym(lib, "JNI_CreateJavaVM");
Expand All @@ -1494,7 +1501,7 @@ namespace jni
{
isVm.store(false);
::dlclose(lib);
throw InitializationException("Java Virtual Machine failed during creation");
JNIPP_THROW(InitializationException("Java Virtual Machine failed during creation"));
}

#endif // _WIN32
Expand Down
16 changes: 15 additions & 1 deletion jnipp.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,19 @@

// Standard Dependencies
#include <cstring>
#include <stdexcept> // For std::runtime_error
#include <string>

// JNIPP by default uses exceptions to communicate errors to the consumers.
// The preprocessor directive should be set by the build script, but in case
// it wasn't, define it here to its expected default value.
#ifndef JNIPP_USE_EXCEPTION
#define JNIPP_USE_EXCEPTION 1
#endif

#if JNIPP_USE_EXCEPTION
#include <stdexcept> // For std::runtime_error
#endif

// Forward Declarations
struct JNIEnv_;
struct _JNIEnv;
Expand Down Expand Up @@ -55,6 +65,7 @@ namespace jni
*/
typedef unsigned char byte_t;

#if JNIPP_USE_EXCEPTION
#ifdef JNIPP_EXCEPTION_CLASS

/**
Expand All @@ -70,6 +81,7 @@ namespace jni
typedef std::runtime_error Exception;

#endif // JNIPP_EXCEPTION_CLASS
#endif // JNIPP_USE_EXCEPTION

// Foward Declarations
class Object;
Expand Down Expand Up @@ -986,6 +998,7 @@ namespace jni
~Vm();
};

#if JNIPP_USE_EXCEPTION
/**
A Java method call threw an Exception.
*/
Expand Down Expand Up @@ -1024,6 +1037,7 @@ namespace jni
*/
InitializationException(const char* msg) : Exception(msg) {}
};
#endif

/*
Array Implementation
Expand Down
6 changes: 6 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ add_executable(main_test main.cpp testing.h)
target_link_libraries(main_test PRIVATE jnipp)
add_test(NAME main_test COMMAND main_test)

if(NOT JNIPP_USE_EXCEPTION_HANDLING)
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_compile_options(main_test PRIVATE -fno-exceptions)
endif()
endif()

add_executable(external_create external_create.cpp testing.h)
target_link_libraries(external_create PUBLIC jnipp ${JNI_LIBRARIES})
target_include_directories(external_create PUBLIC ${JNI_INCLUDE_DIRS})
Expand Down
18 changes: 17 additions & 1 deletion tests/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
jni::Vm Tests
*/


#if JNIPP_USE_EXCEPTION == 1
TEST(Vm_detectsJreInstall)
{
try
Expand Down Expand Up @@ -42,6 +42,7 @@ TEST(Vm_notAllowedMultipleVms)

ASSERT(0);
}
#endif

/*
jni::Class Tests
Expand All @@ -55,6 +56,7 @@ TEST(Class_findByName_success)
ASSERT(!cls.isNull());
}

#if JNIPP_USE_EXCEPTION
TEST(Class_findByName_failure)
{
try
Expand All @@ -69,6 +71,7 @@ TEST(Class_findByName_failure)

ASSERT(0);
}
#endif

TEST(Class_getName)
{
Expand Down Expand Up @@ -430,6 +433,7 @@ TEST(Array_getElement_defaultValue)
ASSERT(s.getElement(0).length() == 0);
}

#if JNIPP_USE_EXCEPTION
TEST(Array_getElement_indexException)
{
jni::Array<int> a(10);
Expand All @@ -444,6 +448,7 @@ TEST(Array_getElement_indexException)
ASSERT(1);
}
}
#endif

TEST(Array_setElement_basicType)
{
Expand All @@ -467,6 +472,7 @@ TEST(Array_setElement_string)
ASSERT(a.getElement(i) == std::to_wstring(i));
}

#if JNIPP_USE_EXCEPTION
TEST(Array_setElement_indexException)
{
jni::Array<std::string> s(10);
Expand All @@ -481,6 +487,7 @@ TEST(Array_setElement_indexException)
ASSERT(1);
}
}
#endif

/*
Argument Type Tests
Expand Down Expand Up @@ -560,15 +567,20 @@ TEST(Arg_ObjectPtr)
int main()
{
// jni::Vm Tests

#if JNIPP_USE_EXCEPTION
RUN_TEST(Vm_detectsJreInstall);
RUN_TEST(Vm_notAllowedMultipleVms);
#endif

{
jni::Vm vm;

// jni::Class Tests
RUN_TEST(Class_findByName_success);
#if JNIPP_USE_EXCEPTION
RUN_TEST(Class_findByName_failure);
#endif
RUN_TEST(Class_getName);
RUN_TEST(Class_getParent);
RUN_TEST(Class_newInstance);
Expand Down Expand Up @@ -606,10 +618,14 @@ int main()
RUN_TEST(Array_copyConstructor);
RUN_TEST(Array_moveConstructor);
RUN_TEST(Array_getElement_defaultValue);
#if JNIPP_USE_EXCEPTION
RUN_TEST(Array_getElement_indexException);
#endif
RUN_TEST(Array_setElement_basicType);
RUN_TEST(Array_setElement_string);
#if JNIPP_USE_EXCEPTION
RUN_TEST(Array_setElement_indexException);
#endif

// Argument Type Tests
RUN_TEST(Arg_bool);
Expand Down