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


define-java-constructor Macros


Define a Java caller, which is a function that calls a Java method or a constructor.




define-java-caller name class-name method-name &key signatures static-p return-jobject non-virtual-p => result

define-java-constructor name class-name &key class-symbol signatures => result

A symbol.
A string.
A string.
A list of strings.
t, nil or :either (the default).
A boolean, default nil.
A boolean. default nil.
A symbol.
name or nil.

The macros define-java-caller and define-java-constructor define a Java caller, which is a function that calls a Java method or a constructor. Once this the caller is defined, calls to name ultimately invoke a Java method or constructor.

class-name must be the full name of a Java class, in the correct case. The '.' in the name may be replaced by '/'.

method-name must be a public method name of the class, with the correct case.

signatures is used for documentation only. If non-nil, it should be a list of strings, where each string is a signature of the Java method. LispWorks creates a documentation string from the list and sets the documentation of name, so that (documentation name 'function) returns it. LispWorks does not parse the strings. signatures is used by the importing interface (see 15.2.1 Importing classes!) to document the definitions it produces.

static-p tells define-java-caller whether it should look for static or non-static methods. If static-p is :either, it tries both. If a call to name with some arguments matches both a static and a non-static method, an error of type java-program-error is signaled. If static-p is t, define-java-caller looks only for static methods, and if static-p is nil, define-java-caller looks only for non-static methods.

By default, when the method is an ordinary method (not static and not constructor), the invocation is virtual (normal Java behavior), which means that if the class of the first argument is a subclass of class-name, then it may invoke a method that is defined in a subclass of class-name. If non-virtual-p is non-nil, it makes the call non-virtual. Note that this is not normal Java behaviour, and may lead to surprising effects. non-virtual-p was added in LispWorks 8.0. When non-virtual-p is non-nil, it makes the caller look only for ordinary methods. If non-virtual-p is non-nil and static-p is t, an error is invoked.

If the return value type is a primitive type, the caller converts the result of the method to the matching Lisp type before returning it. For method signature return types other than java.lang.String and java.lang.Object, the caller returns a jobject representing the Java object, or nil if the method returned null. Constructors always return jobjects.

return-jobject controls the returned value when the method signature return value type is java.lang.String or java.lang.Object. With the default nil, return value java.lang.String is converted to a Lisp string, and return value java.lang.Object is converted to Lisp value when possible (see 15.1 Types and conversion between Lisp and Java). If return-jobject is non-nil, all non-primitive values are returned as jobjects. For any other non-primitive return values in the method signature, a jobject is always returned. Note that name may call different methods with different return value types when called with different arguments.

class-symbol, when it is non-nil, must name a class. It creates a mapping from the class to the constructor info, which allow functions like make-java-instance and create-instance-jobject to construct a jobject for an instance of the class named by class-symbol.

The effect of these macros is to set the symbol function of name to a function (the caller) that calls a method in the class or a constructor of the class. Before performing the first call, the caller looks up and caches all the methods that are defined for class-name and are named method-name, including inherited methods. When it finds more then one method, the caller decides dynamically in each call which of these methods to call, based on the arguments it gets.

For a successful call to name, it needs to be called with the correct arguments for the Java method. For an ordinary method, this must include the object on which the method should be applied, followed by the arguments of the method. For static methods and constructors, the arguments to name are just the arguments to the method/constructor.

For arguments of primitive type or a matching Java class (for example Integer), the Lisp argument must be either a Lisp object of matching type (see 15.1 Types and conversion between Lisp and Java), or a jobject of the corresponding Java class. For strings (that is argument type java.lang.String) the argument must be a string, nil, or a jobject of type java.lang.String. For other non-primitive types, the argument must be a jobject of the correct class or nil. nil is passed as Java null for non-primitive types.

When the called method is an ordinary method (not static and not constructor), the invocation is virtual (normal Java behavior), which means that if the object's class is of a subclass of class-name, it may invoke a method that is defined in a subclass of class-name.

Unlike the functions setup-java-caller and setup-java-constructor, the macros define-java-caller and define-java-constructor do not do any actual lookup, they just set up the symbol function and therefore they do not require running Java to perform the definition. They are also recognized by the LispWorks Editor as definer forms, so source finders like the Editor command Find Source can locate them. These macros are intended as the main method of defining callers. They are produced by the importing interface to actually define the callers.

For callers defined by these macros, the actual lookup happens the first time the caller is invoked, or for define-java-caller by verify-java-caller or verify-java-callers. If the lookup fails during the function call, an error is signaled of type java-class-error (when the class cannot be found) or java-method-error (when no method can be found).

The macros (when successful) return name.

  1. There is no difference in performance between callers defined by these macros and callers defined by setup-java-caller and setup-java-constructor. If you use setup-java-caller and setup-java-constructor in a delivered application then extra machinery is retained.
  2. If you need several define-java-caller forms with the same class, consider using define-java-callers.
  3. If you need many define-java-caller forms with the same class, you may want to use the importing interface. Even if you want to define your own names for the callers, you can either pass name-constructor to the import function, or use write-java-class-definitions-to-file and edit the definitions that it generated (which saves typing the method names).
  4. For methods it is possible to use verify-java-callers or verify-java-caller at run time to check that the methods are found, which is a way of guarding against typing errors in entering the method name.
  5. There is no restriction on defining more than one caller for the same method or constructor.
  6. Unlike for setup-java-caller and setup-java-constructor, name is not evaluated.
See also

15.2.2 Defining specific callers

LispWorks® User Guide and Reference Manual - 01 Dec 2021 19:30:46