All Manuals > LispWorks User Guide and Reference Manual > 41 The LW-JI Package

NextPrevUpTopContentsIndex

init-java-interface

Function
Summary

Initializes the Java interface.

Package

lw-ji

Signature

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

Arguments

jvm-library-path

A string, t or nil.

java-class-path

A string or a list of strings.

option-strings

A list.

jni-env-finder

A function designator, or nil.

java-virtual-machine

A foreign pointer of type java-vm-poi, or t.

class-finder

A function designator or nil.

class-loader-finder

A function designator or nil.

java-to-lisp-debugger-hook

A function designator or nil.

report-error-to-java-host

A function designator or nil.

send-message-to-java-host

A function designator or nil.

Values

result

t or the keyword :no-java-to-lisp.

Description

The function 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.

Note: On Android, init-java-interface is called automatically by the system initialization, so you do not need to (and must not) call it.

init-java-interface may be used to first initialize the Java Virtual Machine (JVM) or can be called with the JVM already running.

Initializing the virtual machine

If 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 t, 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.

java-class-path and option-strings are ignored when init-java-interface is called after the JVM started.

Calling with JVM already running

If init-java-interface is called with the JVM already running, then jvm-library-path must be nil, and either jni-env-finder or java-virtual-machine must be supplied as non-nil.

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 AttachCurrentThread or GetEnv.

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.

Notes

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.

Compatibility note

At the time of writing, the keyword argument java-virtual-machine is not available in LispWorks 7.0

Description (cont.)

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.setErrorReporter and com.lispworks.Manager.setGuiErrorReporter, see the entry for setErrorReporter).

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 :append, :prepend, :append-no-scroll and :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.

See also

Java interface


LispWorks User Guide and Reference Manual - 13 Feb 2015

NextPrevUpTopContentsIndex