Qore jni Module  2.0.0
Qore jni Module

jni Module Introduction

The jni module allows for Java APIs to be used in Qore as if the Java APIs were Qore APIs and vice-versa, as Qore APIs can be dynamically imported into Java programs at runtime; additionally a custom Java compiler implementation is included that allows for building bytecode with the Qore class loader that supports dynamic byte code generation for Qore and Python language bindings; see Importing Qore and Python APIs Dynamically in Java for more information.

Native API imports and bindings as well as run-time data translations between Java and Qore and Java and Python are supported.

Java bytecode generation for dynamic API generation is provided by Byte Buddy, an excellent and flexible open-source API for Java bytecode generation.

This module is released under the MIT license (see COPYING.MIT in the source distribution for more information). The module is tagged as such in the module's header (meaning it can be loaded unconditionally regardless of how the Qore library was initialized).

To use the module in a Qore script, use the %requires directive as follows:

%requires jni

Helper Qore classes provided by this module:

Class Description
JavaArray a convenience class for using Java Arrays in Qore
QoreInvocationHandler a convenience class for executing Qore-language callbacks from Java

Helper Qore functions provided by this module:

Function Description
get_version() Returns the version of the JNI API
implement_interface() Creates a Java object that implements given interface using an invocation handler
invoke() Invokes a method with the given arguments
invoke_nonvirtual() 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
load_class() Loads a Java class with given name and returns a java::lang::Class object
new_array() Creates a JavaArray object of the given type and size
set_save_object_callback() Sets the object lifecycle management callback; see Managing the Lifecycle of Qore objects from Java for more information


Java Dynamic Python Import Example:
// import the "xml" module and all symbols from xml.etree.ElementTree into Java
import pythonmod.xml.etree.ElementTree.*;
// extend the pythonmod.xml.etree.ElementTree.ElementTree class
public class QoreDynamicTest10 extends ElementTree {
// we need to declare that our constructor can throw an exception
public QoreDynamicTest10() throws Throwable {
// parse some XML and then return the value of the given element
public static Object test(String str, String name) throws Throwable {
Element elem = (Element)pythonmod.xml.etree.ElementTree.$Functions.fromstring(str);
Element e0 = elem.find(name);
Object rv = e0.getMemberValue("text");
return rv;
Java Dynamic Qore Import Example:
import java.util.Arrays;
import java.util.Iterator;
// import ::Qore::AbstractIterator as an abstract Java base class
import qore.Qore.AbstractIterator;
// this class wraps a Java Iterator as a Qore AbstractIterator
class QoreIteratorTest extends AbstractIterator {
private Iterator i;
QoreIteratorTest(Iterator i) throws Throwable {
this.i = i;
public boolean next() {
return i.hasNext();
public Object getValue() {
return i.next();
public boolean valid() {
return true;
Qore JMS Example:
#!/usr/bin/env qore
%requires jni
%requires QUnit
%requires Util
# import Java classes to our script
%module-cmd(jni) import javax.naming.InitialContext
%module-cmd(jni) import javax.jms.*
# add environment variable $GLASSFISH_JAR to the dynamic classpath (if set)
%module-cmd(jni) add-classpath $GLASSFISH_JAR
%exec-class Main
public class Main inherits QUnit::Test {
private {
Counter c(1);
auto data;
const TextMsg = "Hello, world!";
constructor() : Test("JMS test", "1.0", \ARGV) {
addTestCase("base test", \testJms());
# Return for compatibility with test harness that checks return value.
testJms() {
# these properties are the default; included here to provide an example for connecting to a remote server
Properties props();
props.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
props.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
props.setProperty("org.omg.CORBA.ORBInitialPort", "3700");
InitialContext ctx(props);
Connection connection =
Session session = connection.createSession(Session::CLIENT_ACKNOWLEDGE);
Destination queue = cast<Destination>(ctx.lookup("abc"));
MessageProducer producer = session.createProducer(queue);
MessageConsumer consumer = session.createConsumer(queue);
# in order to implement the MessageListener interface for the callback, we have to use implement_interface()
# as follows:
ClassLoader loader = connection.getClass().getClassLoader();
new QoreInvocationHandler(\messageCallback()), Class::forName("javax.jms.MessageListener", True,
TextMessage message = session.createTextMessage();
# wait for message to be received
assertEq(TextMsg, data);
# unset the listener and exit
# JMS message callback for the MessageListener interface
messageCallback(Method method, *list args) {
TextMessage msg = args[0];
# ignore redeliveries
if (msg.getJMSRedelivered())
data = msg.getText();
if (m_options.verbose)
printf("*** JMS message received: %y (id: %y)\n", msg.getText(), msg.getJMSMessageID());

JVM Initialization

The JVM is initialized when the module is loaded. It is possible to disable JIT when the module is loaded, however the module is loaded an initialized before module parse commands are processed, therefore to tell the module to disable JIT, the following environment variable must be set to 1:


Using Java APIs in Qore

Importing Java APIs into Qore

To import Java APIs into the Qore program; any of the following jni-module-specific parse directives can be used, each of which also causes the jni module to be loaded and initialized:

  • %module-cmd(jni) import java.namespace.path.*
    imports the given wilcard path or class into the Qore program
  • %module-cmd(jni) add-classpath filesystem/path:another/path
    adds the given paths to the runtime dynamic classpath; supports environment variable substitution
  • %module-cmd(jni) add-relative-classpath ../relative/path
    adds the given paths as relative to the current program to the runtime dynamic classpath

All classes in java.lang.* are imported implicitly. Referencing an imported class in Qore code causes a Qore class to be generated dynamically that presents the Java class. Instantiating a Qore class based on a Java class also instantiates an internal Java object that is attached to the Qore object. Calling methods on the object will cause the same Java methods to be called with any arguments provided.

See also
Java Class and Package Mapping in Qore for more information

Defining Java Classes at Parse Time in Qore

The jni module also supports defining classes at parse time with the following jni-module-specific parse directives:

  • %module-cmd(jni) define-class <name> <base 64 bytecode>
    defines the given class with <name> as the Java internal name for the class (ex: my/package/MyClassName)
  • %module-cmd(jni) define-pending-class <name> <base 64 bytecode>
    adds the given class and bytecode as a pending class to be defined when required by a define-class directive; this should be used for inner classes and has been implemented to allow circular dependencies in such classes to be resolved; <name> is the Java internal name for the inner class (ex: my/package/MyClassName$1)

Setting Java System Properties at Parse Time in Qore

The jni module also supports setting Java system properties at parse time with the following jni-module-specific parse directive:

  • %module-cmd(jni) set-property <propname> <value>
    sets the given property at parse time

Java Class and Package Mapping in Qore

Java Package to Qore Namespace Mapping

The jni module maps Java packages to Qore namespaces. Therefore in Java java.lang.String can be referred to as java::lang::String in Qore as in the following example:

java::lang::String str();

The jni module attempts to create Qore classes that match the source Java class as closely as possible to maximize the usefulness of Java APIs in Qore.

When creating Qore class methods from the corresponding Java source method, types are mapped according to Java to Qore Type Conversions. Because Qore has fewer types than Java, this can lead to method signature collissions in the generated Qore class.

In such cases, only the first method returned by the internal call to java.lang.Class.getDeclaredMethods() is mapped.

To call an unmapped method, use reflection to get a java.lang.Method object and make the call using java.lang.Method.invoke() as in the folllowing example:

StringBuilder stringBuilder("");
Method stringBuilderAppendLong = stringBuilderClass.getMethod("append", Long::TYPE);
stringBuilderAppendLong.invoke(stringBuilder, 20);
printf("%y\n", stringBuilder.toString());

Java Inner Classes in Qore

Java inner classes are mapped as Qore classes by appending "__" to the outer class's name and then appending the name of the inner class.

For example:

class Outer {
public Outer() {
public class Inner {
public Inner() {

The inner class would be created as "Outer__Inner" in Qore.

Subclassing Java Classes in Qore

When subclassing Java classes in Qore, the Qore class code is not executed by Java when dispatching method calls in Java itself. This means that overriding Java methods in Qore is only valid for code executed from Qore.

To override a Java method when called from Java, you must subclass the class in Java as well and import the child class into your Qore program.

One exception to this limitation is with interfaces; programmers can use the QoreInvocationHandler class to execute Qore-language callbacks based on Java interfaces; see the documentation for QoreInvocationHandler for more information.

Java Class Fields to Qore Class Mappings

Java fields are mapped to different Qore class members according to the Java type according to the following table.

Java Field to Qore Class Member Mappings

Java Qore Qore Example
static final Qore class constants
static (non-final) Qore static class members
all others normal Qore class members

For example:

Java field values are only stored in Java; they are not mirrored in Qore. Java field values are accessed with the class's memberGate() method; updating a Java object's field value in Qore will not cause the field value to be updated in Java. To update the field's value from Qore in Java, use java::lang::reflect::Field::set().

Java Access Mapping in Qore

Java access modifiers are mapped directly to Qore access modifiers as in the following table.

Java to Qore Access Mappings

Java Qore
public public
protected private (or private:hierarchy)
private private:internal

Java Classloader

There is a global classloader for all Java objects reachable without special classpath. For all other objects, each Qore Program container has its own custom classloader provided by the jni module that supports a dynamic classpath.

The Qore Program-specific dynamic classpath can be set with the import commands as documented in Importing Java APIs into Qore.

Explicit class loaders can also be used as in Java as in the following example:

softlist<URL> urls = (new URL("file:///my/dir/my-api.jar"));
URLClassLoader classLoader(urls);
Class myClass = classLoader.loadClass("MyClass");
The class loader supplied by this module, org.qore.jni.QoreURLClassLoader, supports dynamic bytecode generation from Python and Qore imports.

Java Exceptions in Qore

If a org.qore.jni.QoreException exception is thrown, then it is mapped directly to a Qore exception.

Other Java exceptions are mapped to the Qore ExceptionInfo hash as follows:

  • err: always "JNI-ERROR"
  • desc: the full Java class name of the exception class; ex: "java.lang.RuntimeException"
  • arg: the exception object itself as a Qore object wrappingg the Java object

Exception locations including call stack locations reflect the actual Java source location(s), and in such cases the lang attribute will be "Java".

Using the jni Module From Java

Java code can use the jni module and Java classes based on Qore code by calling org.qore.jni.QoreJavaApi.initQore() to initialize the Qore library and the jni module with an existing JVM session. This requires the platform-dependent qore library to be found in a directory set in the java.library.path or by setting the QORE_LIBRARY environment variable to the absolute path of the qore library.

If neither of these are set, then calling org.qore.jni.QoreJavaApi.initQore() will result in a java.lang.UnsatisfiedLinkError exception being raised.

All Java classes for Qore support are located in the qore-jni.jar file.

Example Java source:

import org.qore.lang.qunit.*;
class MyTest {
public static void main(String[] args) throws Throwable {
Test test = new Test("MyTest", "1.0");
test.addTestCase("test", () -> doTest(test));
private static void doTest(Test test) throws Throwable {

Example compilation command:

    javac -cp qore-jni.jar MyTest.java

Example run command:

    java -Djava.library.path=/usr/local/lib -cp qore-jni.jar:. MyTest

Importing Qore and Python APIs Dynamically in Java

Dynamic Qore and Python API imports are supported with qore-jni.jar at runtime; qore-jni-compiler.jar contains a compiler API that can build bytecode that supports providing dynamic imports to the Java compiler as well.

At runtime, only the qore-jni.jar file (and an accessible Qore shared library) are needed.

Dynamic Import Statements

The following special packages provide access to dynamically-generated classes:

  • python.[path...]: indicates that the given path should be imported from Python to Java (after being imported to Qore if necessary).
  • pythonmod.mod.[path...]: indicates that the given path should be mapped to Qore namespaces and/or classes after loading the Python module mod and importing into Qore; the Java package segments after pythonmod.mod. are then converted to the equivalent Qore namespace path
  • qore: indicates that the given path should be mapped to Qore namespaces and/or classes; the Java package segments after qore. are then converted to the equivalent Qore namespace path
  • qoremod.mod.[path...]: indicates that the given path should be mapped to Qore namespaces and/or classes after loading the Qore module mod; the Java package segments after qoremod.mod. are then converted to the equivalent Qore namespace path

For example:

  • import python.os.$Functions would import all functions in the os module to Java in the python.os.$Functions class, assuming the os module has already been imported into Python beforehand, otherwise to import a Python module and then import symbols from that module, use the following option
  • import pythonmod.json.JSONEncoder; would cause the json Python module to be loaded and imported into Qore and then for the JSONEncoder class to be imported into Java automatically
  • import qore.Qore.Thread.ThreadPool; would cause the Qore ::Qore::Thread::ThreadPool class to be imported automatically into Java
  • import qoremod.RestClient.RestClient; would cause the RestClient Qore module to be loaded and then for the RestClient class to be imported automatically

Qore and Python classes imported as above can then be used as Java classes for instantiation or as base classes for Java subclasses.

  • Qore acts as a "language bridge" between Python and Java; Python can also inherit Java classes using a similar mechanism; Java classes are imported into Qore and then the wrapper Qore classes are imported dynamically into Python
  • Python and Qore classes from modules can be imported in two different ways as per above, each import variant results in a Java class with a binary path specific to the import statement
Importing Functions Into Java

Qore and Python functions can be imported using the special $Functions class name; functions in a Qore namespace are imported automatically into a special class with this name in the corresponding dynamic Java package.

Importing Constants Into Java

Qore constants can be imported using the special $Constants class name; constants in a Qore namespace are imported automatically into a special class with this name as static final fields in the corresponding dynamic Java package.

Using Dynamic API Imports While Compiling

The org.qore.jni.compiler.QoreJavaCompiler class must be used to compile bytecode using dynamic imports.

The standard javac program wil not work, because it is not capable of understanding or generating the bytecode for the dynamic imports in the special Java package.

Here is a Java example using the compiler:

import org.qore.jni.compiler.QoreJavaCompiler;
import org.qore.jni.compiler.CompilerOutput;
import java.nio.file.Files;
// compile and execute QoreDynamicTest.java
class MyCompiler {
public static void main(String[] args) {
QoreJavaCompiler compiler = new QoreJavaCompiler();
CompilerOutput newClassData = compiler.compile("org.qore.test.QoreDynamicTest",
Files.readString("./QoreDynamicTest.java", StandardCharsets.UTF_8));
// get byte code with: newClassData.file.openInputStream().readAllBytes()
Object obj = newClassData.cls.getDeclaredConstructor().newInstance();
// ...

And here is a Qore example:

#!/usr/bin/env qore
# -*- mode: qore; indent-tabs-mode: nil -*-
%requires jni
%module-cmd(jni) add-relative-classpath $MY_JARS/qore-jni.jar
%module-cmd(jni) add-relative-classpath $MY_JARS/qore-jni-compiler.jar
%module-cmd(jni) import org.qore.jni.compiler.CompilerOutput
# compile and execute QoreDynamicTest.java
QoreJavaCompiler compiler();
compiler::CompilerOutput newClassData = compiler.compile("org.qore.test.QoreDynamicTest",
File::readTextFile(get_script_dir() + "/QoreDynamicTest.java"));
# get byte code with: newClassData.file.openInputStream().readAllBytes();
Object obj = newClassData.cls.getDeclaredConstructor().newInstance();
# ...
the qjava2jar helper script can be used to compile Java sources using dynamic imports to a jar file; ex:
qjava2jar my-jar.jar source_path -cp some-api.jar:another-api.jar -nowarn 

JNI Module Compatibility Options

This module supports the following compatibility option: "compat-types" which, when enabled, will disable the following type conversions:

  • Java byte[] to binary; instead this will converted to list<int>
  • Java java.util.Map to hash; instead this will be converted directly

This option can be set globally for all Program objects with set_module_option("jni", "compat-type", True) or locally for the current Program container with the set-compat-type module parse option like: module-cmd(jni) set-compat-type true or module-cmd(jni) set-compat-type false to override the global setting.

Type Conversions Between Qore and Java

The jni module uses reflection to automatically map Java classes to Qore classes. This class mapping and Qore class creation happens at parse time (when importing Java APIs into Qore) and also at runtime (if a new class is encountered that has not already been mapped).

There are two types of conversions from Qore to Java:

Qore to Java Defined Type Conversions

The following table describes type conversions for Java types when the jni module must convert a Qore value to the declared type:

Qore to Specific Java Type Conversions

Target Java Type Source Qore Type
boolean any; conversions are made like with boolean()
byte any; conversions are made like with int()
char any; conversions are made like with int()
short any; conversions are made like with int()
int any; conversions are made like with int()
long any; conversions are made like with int()
float any; conversions are made like with float()
double any; conversions are made like with float()

For other types, default conversions are used.

Qore to Java Default Type Conversions

The following table describes type conversions for Java types when the jni module must convert a Qore value to the declared type:

Qore to Java Default Type Conversions

Source Qore Type Target Java Type
bool boolean
int long
float double
string java.lang.String
date java.lang.Object (compile time) or java.time.ZonedDateTime or org.qore.jni.QoreRelativeTime (runtime)
number java.math.BigDecimal
binary byte[]
list java Arrays of the list type; if no list type can be found, then the Array type is java.lang.Object
hash org.qore.jni.Hash (extends java.util.LinkedHashMap), however any type implementing java.util.Map that has a constructor that takes no arguments and a compatibule put() method will be constructed / converted automatically to the desired type
code (closure or call reference) org.qore.jni.QoreClosure
JavaArray java.lang.Array
object to the Java class if the Qore object is an instantiation of java.lang.Object, otherwise org.qore.jni.QoreObject
all jni objects direct conversion
  • Qore 64-bit integers are automatically converted to 32-bit Java integers; to get a Java long value; use:
    new Long(val)
  • see Java Arrays for more information about conversions between Qore lists and Java arrays

Java to Qore Type Conversions

Java to Qore Type Conversions

Source Java Type Target Qore Type
boolean bool
byte int
byte[] binary (see also JNI Module Compatibility Options)
char int
short int
int int
long int
float float
double double
java.lang.String string
java.time.ZonedDateTime date (absolute date)
org.qore.jni.QoreRelativeTime date (relative date)
java.math.BigDecimal number
java.lang.AbstractArray and arrays list
java.util.Map hash (see also JNI Module Compatibility Options)
@ref org.qore.jni.QoreClosure code
org.qore.jni.QoreClosureMarker code
all other objects direct conversion
see Java Arrays for more information about conversions between Qore lists and Java arrays

Java Arrays

Arrays are mapped directly to and from Qore lists. When converting from a Qore list to a Java array, the list is scanned, and if it can be mapped to a single Java type, then an array of that type is created. Otherwise, an array of java.lang.Object is created and the Qore values are mapped directly to Java values.

Qore lists are passed by value and Java arrays are objects (which, like Qore objects, are passed with a copy of a reference to the object). To get similar functionality in Qore, you can use the JavaArray class supplied with the jni module, which is automatically converted to a Java array object like a list, but is also passed with a copy of a reference to the object in Qore.

Java Arrays as Variable Arguments

When a Java method declares variable arguments, such arguments must be generally given as a single array value (so a Qore list or JavaArray object). Consider the following example:

StringBuilder stringBuilder("");
lang::Class stringBuilderClass = lang::Class::forName("java.lang.StringBuilder");
Method stringBuilderAppendLong = stringBuilderClass.getMethod("append", (Long::TYPE,));
stringBuilderAppendLong.invoke(stringBuilder, (20,));
printf("%y\n", stringBuilder.toString());

In the above example, the java.lang.Class.getMethod() and the java.lang.Method.invoke() methods both take a variable number of arguments after the first argument. In the mapped Qore class, these must be given as a Qore list (as in the above example) or a JavaArray object.

If the last argument of a Java method has an array type, then the arguments in Qore can also be given in the flat argument list, and the final array argument will be created automatically for the call.

Because of this, the example above also works as follows:

StringBuilder stringBuilder("");
lang::Class stringBuilderClass = lang::Class::forName("java.lang.StringBuilder");
Method stringBuilderAppendLong = stringBuilderClass.getMethod("append", Long::TYPE);
stringBuilderAppendLong.invoke(stringBuilder, 20);
printf("%y\n", stringBuilder.toString());

Managing the Lifecycle of Qore objects from Java

Qore's deterministic garbage collection approach and reliance on destructors means that Qore objects created by Java must have their lifecycles managed externally.

Java objects wrapping Qore objects (such as org.qore.jni.QoreObject and org.qore.jni.QoreObjectWrapper) hold only weak references to Qore objects.

Java methods in the jni module that explicitly save strong references to Qore objects are as follows:

The strong reference to any Qore object returned by the preceding methods is managed in one of two ways described in the following sections.

Default Qore Object Lifecycle Management

By default, Qore objects are saved in thread-local data, so the lifecycle of the object is automatically limited to the existence of the thread.

The thread-local hash key name used to save the list of objects created is determined by the value of the "_jni_save" thread-local key, if set. If no such key is set, then "_jni_save" is used instead as the literal key for saving the list of objects.

Explicit Qore Object Lifecycle Management

The lifecycle of Qore objects can be managed explicitly by using the set_save_object_callback() function to set a callback that is called every time a Qore object is created using the Java API.

This callback must take a single object argument as in the following example:

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;

jni Module Release Notes

jni Module Version 2.0

  • Qore int values are now converted to Java long in order to maintain precision
  • the old hand-developed Java wrapper classes are deprecated as of this release in favor of dynamic imports
  • implemented support for dynamically importing Qore code into Java (issue 4091)

jni Module Version 1.2

  • fixed method calls for methods that return base types where a caller context is required (for Reflection access control, for example) (issue 4093)
  • fixed a memory leak (or an assertion crash in debug mode) for a duplicate member error when importing Java classes in Qore (issue 4029)
  • added support for converting Qore closures / call references to a Java object (issue 3995)

jni Module Version 1.1.3

jni Module Version 1.1.2

  • use java.util.List<?> instead of java.util.ArrayList<?> as the base class for list conversions (issue 3873)
  • added the org.qore.jni.Hash class to use when passing Qore hashes to Java to make it easier to work with Qore hash data (issue 3868)
  • fixed a crash in Qore Program setup when initiated from a Qore thread with no Java context thread (issue 3862)
  • fixed a crash in method invocation due to incorrect detection of the Java thread context (issue 3794)
  • fixed a bug in SmtpClient.sendMessage()

jni Module Version 1.1.1

jni Module Version 1.1

jni Module Version 1.0.1

  • fixed setting the class loader context when calling Qore code from Java threads (issue 3585)

jni Module Version 1.0

  • initial public release
Definition: CompilerOutput.java:8
set_save_object_callback(*code save_object_callback)
Sets the "save object" callback for Qore objects created from Java code.
Definition: QoreJavaCompiler.java:74
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.