//! Jni namespace
namespace Jni {
//! org namespace
namespace org {
//! qore namespace
namespace qore {
//! jni namespace
namespace jni {
/** @defgroup JNI functions.
///@{
 */

//! Creates a class object from bytecode data
/** @par Example:
    @code{.py}
java::lang::Class cls = define_class(name, bytecode);
    @endcode

    @param name the name of the class (ex: \c "org/qore/my_package/ClassName")
    @param bytecode the byte code of the class

    @note the class will be created using the classloader for the containing %Program object

    @since %jni 1.1
*/
Jni::org::qore::jni::Class define_class(string name, binary bytecode);

//! Returns dynamically generated Java byte code for the given %Qore class
/** @par Example:
    @code{.py}
binary byte_code = get_byte_code("::Qore::Thread::Condition");
    @endcode

    @param class_name the class name (can include a namespace path) to the %Qore class

    @return the dynamically generated Java byte code for the class

    @throws CLASS-NOT-FOUND the %Qore class could not be found

    @note Other exceptions can also be thrown during bytecode generation

    @since jni 2.0
*/
binary get_byte_code(string class_name);

//! Returns the class loader associated with the current program
/** @par Example:
    @code{.py}
ClassLoader loader = get_class_loader();
    @endcode

    @return the class loader associated with the current program

    @since jni 2.0
*/
Jni::java::lang::Object get_class_loader();

//! Returns the version of the JNI API.
/**@return the version of the JNI API
 */
string get_version();

//! Creates a Java object that implements given interface using an invocation handler.
/**@param invocationHandler the invocation handler
    @param cls the interface to implement
    @return a Java object that implements the interface by calling the invocation handler

    @par Example:
    @code{.py}
    Class runnableClass = Jni::load_class("java/lang/Runnable");
    QoreInvocationHandler h(any sub(Method m, *list args) { doRun(); });
    Object runnableInstance = Jni::implement_interface(h, runnableClass);
    # runnableInstance now has a Java method void run() that calls Qore function doRun()
    @endcode
 */
Jni::java::lang::Object implement_interface(Jni::org::qore::jni::QoreInvocationHandler invocationHandler, Jni::java::lang::Class cls);

//! Creates a Java object that implements given interface using an invocation handler using an explicit class loader.
/**@param classLoader the class loader that loaded the interface
    @param invocationHandler the invocation handler
    @param cls the interface to implement
    @return a Java object that implements the interface by calling the invocation handler

    @par Example:
    @code{.py}
    ClassLoader classLoader = ...;
    Class runnableClass = load_class("java/lang/Runnable");
    QoreInvocationHandler h(any sub(Method m, *list args) { doRun(); });
    Object runnableInstance = Jni::implement_interface(classLoader, h, runnableClass);
    # runnableInstance now has a Java method void run() that calls Qore function doRun()
    @endcode
 */
Jni::java::lang::Object implement_interface(Jni::java::lang::ClassLoader classLoader, Jni::org::qore::jni::QoreInvocationHandler invocationHandler, Jni::java::lang::Class cls);

//! Invokes a method with the given arguments in a virtual way; meaning that the method in the most derived class is executed; not necessarily the method passed as an argument
/** @param method the method to invoke
    @param object the object to use to invoke the method; for static methods, this argument can be @ref nothing

    @note
    - reflection is not used, so exceptions are thrown directly (i.e. not wrapped as \c java.lang.reflect.InvocationTargetException objects)
    - for static method invocations, this function is identical to @ref invoke_nonvirtual()
 */
Jni::java::lang::Object invoke(Jni::java::lang::reflect::Method method, __7_ Jni::java::lang::Object object,  ...);

//! Invokes a method with the given arguments in a non-virtual way; meaning that even if the object provided is a child class, the method given in the first argument is executed
/** @param method the method to invoke
    @param object the object to use to invoke the method; for static methods, this argument can be @ref nothing

    @note
    - reflection is not used, so exceptions are thrown directly (i.e. not wrapped as \c java.lang.reflect.InvocationTargetException objects)
    - for static method invocations, this function is identical to @ref invoke()
 */
Jni::java::lang::Object invoke_nonvirtual(Jni::java::lang::reflect::Method method, __7_ Jni::java::lang::Object object,  ...);

//! Loads a Java class with given name.
/**@param name the name of the class to load in internal (\c "java/lang/String") format

    @return the loaded class

    @throws JNI-ERROR if the class cannot be loaded

    @par Example:
    @code{.py}
    Class c = Jni::load_class("java/lang/String");
    @endcode
 */
Jni::java::lang::Class load_class(string name);

//! Allocates a new Java array
/** @param cls the Class of the component type of the Array
    @param size the size of the array to allocate

    @return the allocated array
 */
Jni::org::qore::jni::JavaArray new_array(Jni::java::lang::Class cls, int size);

//! Sets the "save object" callback for %Qore objects created from Java code
/** @par Restrictions:
    @ref Qore::PO_NO_PROCESS_CONTROL

    @par Example:
    @code{.py}
hash<string, object> object_cache;
code callback = sub (object obj) {
    # save object in object cache, so it doesn't go out of scope
    object_cache{obj.uniqueHash()} = obj;
}
set_save_object_callback(callback);
    @endcode

    @param save_object_callback the callback to save any %Qore objects created in Java code, must take an argument of
    type @ref object_type "object"

    Due to the differences in garbage collection approaches between %Qore and Java, %Qore objects must be managed with
    a deterministic life cycle; Java objects have only weak references to %Qore objects due to the lack of
    destructors in Java and the lack of determinism in the JVM for object lifecycle management.

    The callback set here will be called any time a %Qore object is created from Java code; if no callback is set,
    then the standard thread-local implementation is used where %Qore objects are saved in a thread-local hash.

    @see @ref jni_qore_object_lifecycle_management for more information
*/
 set_save_object_callback(__7_ code save_object_callback);

///@}
}
}
}
}
