| Allegro CL version 9.0 New since 9.0 release. |
Arguments: &key jar init-args classpath keep classes mode out package names exclude rename
This operator was added in a patch release in April, 2014.
This function analyzes a collection of Java libraries and classes to generate Lisp functions that call Java methods and constructors through a Jlinker connection.
Each Java instance method name is mapped to a Lisp function with a corresponding Lisp name. Overloading is handled by dynamic dispatch in Lisp. More details on this later.
Each Java static method name is mapped to a Lisp name composed from the class name and method name.
Java constructors are mapped to a Lisp name derived from the class name.
Each static final field is mapped to a Lisp name derived from the class name and field name. The Lisp function caches the value in Lisp so that repeated uses of the field do not require round-trips to Java.
The scan and analysis is done by calling Java reflection API methods. Therefore, Java and the required jar files must be available during the scan and code generation.
The generated code is sensitive to the case-mode of both the
generating and running Lisp. In most cases code generated
in :break
mode in mlisp will run equally
well in alisp or mlisp. Code generated
in :keep
mode in mlisp is most likely to cause
problems when run in alisp. (mlisp is the case-sensitive modern
Common Lisp version. alisp is the case-insensitive Common
Lisp. See case.htm for details of case sensitivity
in Allegro Common Lisp.
jar: A jar file entry or a list of jar file entries:
jar-file-entry -> path-string | (path-string filter... ) filter -> :include reg-exp-string -> :exclude reg-exp-string
Each filter is applied in turn to each name in the jar file manifest.
Very often, a jar file contains many entries above and beyond the documented public api in a library. There is little benefit in generating Lisp names for all the internal names of the library.
init-args: A list of initial arguments to jlinker-init.
classpath: A list of additional classpath components.
If Jlinker is already running when scan-java-api is called, then both init-args and classpath are ignored.If Jlinker is not running, jlinker-init is called with the specified arguments. A classpath argument is added to this list by combining the classpath argument with the list of jar files.
The remaining keyword arguments are:
nil
(default
is nil
), scan-java-api saves the collected class
and method data as the value
of user::*jscan-java-api-data*
. This information
may be of some value in reporting a problem in API generation.
:gen
(the default) - Analyze and generate Lisp
code.
:walk
- Analyze the class tree and return a list of
all methods and fields.
:gen
and out
is nil
, then mode
switches to :walk
. Two output files are generated:
:gen
and package
is nil
, then mode
switches to :walk
.
A new package is created, using no other packages. All the generated function names are exported from this package.
If several jar files are involved, there may be Lisp name conflicts. In that case, the code generation may need to be split among two or more packages and the code generated into separate output files. The functions in each Lisp package must be generated with separate calls to the generator function.
If the generator is called twice for different libraries but the same output package, conflicts between the two sets of functions will not be detected when the code is generated; the conflicts may be detected when the generated code is loaded.
:break
. The
choices are:
:keep
- generate the Lisp name from the exact
spelling of the Java name, but remain sensitive to Lisp input case
mode by interning symbols with read-from-string. This style is likely
to cause problems in ANS Lisp (alisp) and thus is recommended
only in mlisp (Modern) mode. Here are some examples when using
:keep
:
Instance method addItem maps to Lisp function jpk:addItem Static method close in class com.foo.SomeClass maps to Lisp function jpk:SomeClass.close Constructor for class com.foo.SomeClass maps to Lisp function jpk:new-SomeClass Accessor for static final field foo in com.foo.SomeClass is Lisp function jpk:SomeClass.foo
:break
- generate a Lisp name similar to the Java
name and avoid any case issues. This style may generate name
conflicts in some cases (see the exclude arg
below). Here are some examples using :break
:
Instance method addItem maps to Lisp function jpk:add-item Static method close in class com.foo.SomeClass maps to Lisp function jpk:some-class-close Constructor for class com.foo.SomeClass maps to Lisp function jpk:new-some-class Accessor for static final field foo in com.foo.SomeClass is Lisp function jpk:some-class-foo
:keep-case
- generate the Lisp name from the exact
spelling of the Java name and bypass Lisp input case conversion by
using intern explicitly. This
method is the same as :keep
in Modern mode
(mlisp). When used in ANS mode (alisp), the code must
be generated and compiled in ANS mode and can only run in ANS
Lisp. Most Java names will need to be escaped in any application code.
See the table below for all the possible case-mode and names variations.
({ :method | :static } [method-regexp [class-regexp
[(signature-regexp...)]]])
-- skip code generation for for
the specified method or methods. If the class
and
signature
regexps are omitted, skip code generation
for any method with a matching name. If
the class-regexp
is present, skip only methods in
matching classes. If the signature regexps are specified, skip only
methods with that many arguments where the arguments match.
A nil
or an empty string will match anything.
(:constructor [class-regexp
[(signature-regexp...)]])
(:final class-regexp field-regexp)
( Java-spec Lisp-name-spec )
where Lisp-name-spec
may be a string or a symbol. A
string denotes a symbol in the generated code package. A symbol is
used as specified. If the symbol is not in the generated code
package, the generated output file will assume that the needed package
exists.
Java-spec
: All the strings in the Java-spec must
match the Java class or method name exactly. The Java-specs can be:
(:static name [class [signature]]) (:method name [class [signature]]) -- If class and signature are omitted, the Lisp name is used for all methods with the given name. If class is specified, only methods in that class are affected. If signature is specified, the Lisp name is used for exactly one method. (:final class name) -- The specified final static field will have the specified Lisp accessor function. (:constructor class [signature])
Here is a table of consequences of the various values for the names argument:
:names argument | ACL general | ACL compile | ACL run | Notes |
:break |
ANSI | ANSI | ANSI only | |
:break |
Modern | Modern | ANSI and Modern | |
:keep |
ANSI | ANSI | ANSI only | |
:keep |
Modern | Modern | Modern | |
:keep |
Modern | Modern | ANSI | Conflicts likely |
:keep |
ANSI | ANSI | ANSI | |
:keep |
Modern | Modern | Modern |
All other case-mode combinations are likely to produce conflicts and errors at code generation, compile or load time, and likely garbled results at run time.
Lisp name conflicts occur when two or more Java names map to the same generated Lisp name. When a conflict is detected, a message is printed to the console; the first definition detected for this name is emitted, but any subsequent code is suppressed for that Lisp name. A summary of all the conflicts is inserted at the end of the generated code file.
When Java names cause conflicts in Lisp, there are several actions possible:
The generated Lisp functions attempt to dispatch overloaded Java methods by analyzing the Java classes of the instance and other arguments. An available method is a potential match if the instance and argument classes are subclasses of the declaring method and declared signature parts. If this results in more than one match, then declaring classes are compared and any methods declared on a superclass are discarded. If there are still more than one method remaining, and error is signaled. No attempt is made to order the methods by their signatures.
This strategy is similar to but not identical to the way methods are dispatched by the Java compiler. In some cases, the Lisp code identifies more than one method; in some cases it may be unable to match the Lisp arguments to the declared method signatures; in these case an error is signaled.
Java classes Fine extends Narrow; Narrow extends Broad Java methods on class Foo convert(Narrow x) convert(Broad x) Lisp call (convert instance-of-Foo, instance-of-Fine) Dispatcher will find two convert methods.
It is also possible to call the wrong method when the intent is to call a method more general than the most specific. In Java the situation is handled by casting the argument, but there is no way to cast the argument in Lisp. These situations must be recognized by the programmer.
In some of these cases, the solution is to call the desired method explicitly with jcall, jstatic, or jnew. In some, there is no way to call the method with jlinker:
See jlinker.htm for more information on the jLinker facility.
Copyright (c) 1998-2019, Franz Inc. Oakland, CA., USA. All rights reserved.
This page is new in the 9.0 release.
Created 2019.8.20.
| Allegro CL version 9.0 New since 9.0 release. |