Function | Package: net.jlinker | ToC | DocOverview | CGDoc | RelNotes | FAQ | Index | PermutedIndex
| Allegro CL version 9.0 New since 9.0 release.

## scan-java-api

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.

### Arguments:

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:

- keep: When non-`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.
- classes: A Java class name or a list of class names. The classes mentioned in this argument are included in the analysis and code generation. This argument may also include the names of lists of classes defined with def-japi-classes.
- mode: Specifies the result of the call. The choices are:
  - `:gen` (the default) - Analyze and generate Lisp code.
  - `:walk` - Analyze the class tree and return a list of all methods and fields.
  - :flat - Analyze and return a flat list of methods.
- out: A pathname for the output file. If mode is `:gen` and out is `nil`, then mode switches to `:walk`. Two output files are generated:
  - out.cl is the generated Lisp code.
  - out.txt is a cross-reference listing of Lisp and Java names.
- package: A name for the Lisp package where the generated functions will reside. If mode is `: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.

- names: Specifies the method used to generate Lisp names. The default is `: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.

- exclude: A list of method or class names for which Lisp functions should not be generated. Each entry in the list may be a name regexp or a list of the form
  - class-or-method-regexp -- skip code generation for any Java member if the class name or member name contains this regexp
  - `({ :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)`
- rename: A list of entries that specify alternate Lisp names for Java members. Each entry is of the form

             ( 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:

  - a string -- All Java methods with this name will be mapped to the specified Lisp name.

        	(: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.

### Name conflicts in Lisp:

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:

- Ignore the conflict. In this case, the conflicting Java members can only be reached by explicit reference through the jlinker funcall API.
- Add an exclude spec to the scan-java-api call to suppress the conflict notification. The Java members are accessed as above.
- Add a rename spec to the scan-java-api call to specify alternate Lisp names for the conflicting members.

### Dynamic Dispatch of Java methods:

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.

### Example:

         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.

|  | ToC | DocOverview | CGDoc | RelNotes | FAQ | Index | PermutedIndex
| Allegro CL version 9.0 New since 9.0 release.