init-java-interface &key jvm-library-path java-class-path option-strings jni-env-finder java-virtual-machine class-finder class-loader-finder java-to-lisp-debugger-hook report-error-to-java-host send-message-to-java-host => result
A string or a list of strings.
A function designator, or
A foreign pointer of type java-vm-poi, or
A function designator or
A function designator or
init-java-interface needs to be called before using any of the runtime part of the Java interface. That includes the interface functions that are documented as requiring Java, and any of the user-defined callers. The definers in general do not need running Java, but the importing interface does.
init-java-interface needs to initialize the JVM, it must be called with jvm-library-path either
t or the path of a dynamic library, and jni-env-finder must be
nil. When jvm-library-path is
init-java-interface uses a default library path, which is currently
"jvm.dll" on Microsoft Windows,
"/System/Library/Frameworks/JavaVM.framework/JavaVM" on Mac OS X, and
"-ljvm" on other Unix variants. The library must implement the JVM, which means exporting the JNI functions. It loads this library by
fli:register-module, and then initializes it using
JNI_CreateJavaVM. The keyword arguments java-class-path and option-strings can be used to pass options to
JNI_CreateJavaVM. Except on Mac OS X, passing jvm-library-path
t can work only if the library path contains the JVM library.
java-class-path specifies the class path(s) for additional classes on top of the system ones. It is used to specify the
-Djava.class.path option. If java-class-path is a string, it is passed as is, and may contain more than path separated by the appropriate separator (
#\: on Unix,
#\; on Windows), for example
"/myhomedir/myjavaclass;/systemdir/systemjavaclasses/". If it is a list, each string should be a path. Each path needs to specify either a directory containing JAR files, or a full path of a JAR file.
If you want to make calls from Java to Lisp, you will need to have the Java class com.lispworks.LispCalls. com.lispworks.LispCalls is defined in the JAR file
lispcalls.jar which is part of the LispWorks distribution in the
etc directory, that is
(lispworks-file "etc/lispcalls.jar"), so this JAR file will have to be on the path. If you develop for Android and want to import Android classes, you will need the
android.jar on the path too.
option-strings can be used to pass options to
JNI_CreateJavaVM. Each element of option-strings is either a string or a cons of two strings. An element which is a string is passed as the option string (slot
optionString of the
JavaVMOption C struct). For a cons, the car is passed as the option string, and the cdr as the extra info (slot
extraInfo in the
JavaVMOption). Note that that you should not use the option
-Djava.class.path when using the java-class-path argument.
If jni-env-finder is used it must be a function of no arguments and returns a pointer to the JNI environment for the current thread. The result of the finder must be a foreign pointer of type jni-env-poi, corresponding to the C pointer
JNIEnv*. The finder needs to cope with being called on any thread, and the result needs to be valid until the thread dies, and implementing code must deal with eliminating it when the thread goes. In general, this function needs to know how to find the Java virtual machine, and then use the JNI functions
If jni-env-finder is
nil, then java-virtual-machine is used. It can be either
t, which tells the system to find the Java Virtual Machine, or a foreign pointer of type java-vm-poi, which corresponds to the C type
JavaVM*. If java-virtual-machine is
t, the system finds the virtual machine using
JNI_GetCreatedJavaVMs, otherwise it uses the pointer as the virtual machine.
The simple option when the JVM is already running is just passing java-virtual-machine
t. However, the function that the system uses,
JNI_GetCreatedJavaVMs, is a relic from the time when Java allowed more than one Java VM in each process, which it no longer allows. So in principle some day it may be eliminated (Android already does not define it, but on Android the system calls
init-java-interface with jni-env-finder, so this does not matter). On the other hand it is documented in the latest version (8) without any indication that it is deprecated.
You may have a pointer to the Java VM to pass to
init-java-interface either because you got it from code that started the Java VM (by
JNI_CreateJavaVM), or by exporting
JNI_OnLoad from a dynamic library. However, it is not a good idea to export
JNI_OnLoad as a foreign callable from LispWorks when it is delivered as a dynamic library, because it will have to wait until LispWorks finished initialization. See Loading a LispWorks dynamic library into Java.
class-finder specifies a class finder function to be used if the normal search fails. It must be a function taking a string argument, and return a jobject representing a class for this string (for example, a caller for the method
java.lang.Class.forName does the right thing). It is useful when the application knows how to find classes which are not visible from the system class loader. On Android, class-finder is passed with a function that calls
java.lang.Class.forName with the application Class loader, which will find all classes in the application.
class-loader-finder is used when initializing the LispCalls. If it is non-nil, it must be a function of no arguments that returns a ClassLoader jobject. It is called once during initialization, and the result is stored to be used to find the interfaces when initializing a proxy definition. On Android, it is passed with a function that returns the application class finder. You need to be a Java expert to use this option.
java-to-lisp-debugger-hook, when supplied, must be either a function of one argument or
nil. When it is a function, it will be called when the debugger is invoked inside a call from Java to Lisp. The argument is a
cl:condition object describing the problem. The function needs to do something to inform the user of the problem but not actually interactively, and return. The caller will then return a default value to Java. By default there is a hook that logs a bug form (by log-bug-form) and prints a message to the console. On Android, it is set to a function that logs the error and then invokes the user Java error reporters (set in Java by
com.lispworks.Manager.setGuiErrorReporter, see the entry for
report-error-to-java-host, when supplied, must be a function of two arguments, both of which are strings. When it is passed, if the function report-error-to-java-host is called it uses this function to actually do the report. The first argument is assumed to the error string and the second a filename where there is a bug form, or
nil. The function should report to the Java host, whatever that actually means. This keyword is used by the Android interface to set a function that calls into the Android Java code and invokes the same user Java error reporters that are used for the debugger hook above.
The system does not call report-error-to-java-host itself, so the context in which the function may be called is defined by your calls to it. However, it is intended to be used in error handlers, which means it should be able to cope with any context. The default function just prints to
cl:*terminal-io*, which may be useful enough when just debugging.
send-message-to-java-host, when supplied, must be a function of two arguments: a string which is the message and a keyword, one of
:reset, which tells it how to deal with it. If the keyword is
:reset, the "messages output" should be reset, otherwise the string should be added to the "messages output" as appropriate. The meaning of "messages output" and the actual behavior is up to the function. On Android it is supplied a function that ends up calling the method
com.LispWorks.Manager.addMessage. The default function checks the keyword and then writes the string to
cl:*terminal-io*, which is probably good enough for testing purposes.
init-java-interface returns either
t for success, or
:no-java-to-lisp when it is successful but failed to initialize Java-to-Lisp calls, so you cannot call from Java to List or use Lisp proxies. This failure would normally mean that it failed to find the class com.lispworks.LispCalls.
LispWorks User Guide and Reference Manual - 13 Feb 2015