contribs are loaded, JSS can be required and used:
```
-(require #:jss)
+(require '#:abcl-contrib)
+(require '#:jss)
(use-package '#:jss)
```
```
(defun read-image (pathname)
- (#"read" 'javax.imageio.ImageIO (new 'java.io.FileInputStream (namestring pathname))))
+ (#"read" 'javax.imageio.ImageIO (new 'java.io.File (namestring pathname))))
```
To note here is the use of `NEW` from JSS with a symbol for the class
to invoke the method `read` in a bit of a simpler way than using the FFI
calls directly.
-Since we can't "import" Java names, we're stuck with either using
-symbols like this, or caching them in (shorter) variables.
+JSS will automatically "import" Java names, so the same function can
+simply be the following instead (provided that the names aren't
+ambiguous):
-For comparison, the raw FFI would be a bit more verbose:
+```
+(defun read-image (pathname)
+ (#"read" 'ImageIO (new 'File (namestring pathname))))
+```
+
+The names will be looked up again on every call though, so this option
+isn't the best performing one.
+
+For comparison, the raw FFI would be a bit more verbose, but explicitely
+specifies all names:
```
(defun read-image (pathname)
- (jstatic "read" "javax.imageio.ImageIO" (jnew "java.io.FileInputStream" (namestring pathname))))
+ (jstatic "read" "javax.imageio.ImageIO" (jnew "java.io.File" (namestring pathname))))
```
Though with a combination of JSS and cached lookup it could be nicer,
```
(defvar +image-io+ (jclass "javax.imageio.ImageIO"))
-(defvar +file-input-stream+ (jclass "java.io.FileInputStream"))
+(defvar +file+ (jclass "java.io.File"))
(defun read-image (pathname)
- (#"read" +image-io+ (jnew +file-input-stream+ (namestring pathname))))
+ (#"read" +image-io+ (jnew +file+ (namestring pathname))))
```
At this point without other improvements (auto-coercion of pathnames,
```
(defun build-index (index-name pathnames)
(let ((global-document-builder
- (new 'net.semanticmetadata.lire.builders.GlobalDocumentBuilder
- (jclass "net.semanticmetadata.lire.imageanalysis.features.global.CEDD")))
+ (new 'GlobalDocumentBuilder (find-java-class 'CEDD)))
(index-writer (#"createIndexWriter"
- 'net.semanticmetadata.lire.utils.LuceneUtils
+ 'LuceneUtils
index-name
+true+
- (jfield "net.semanticmetadata.lire.utils.LuceneUtils$AnalyzerType" "WhitespaceAnalyzer"))))
+ (get-java-field 'LuceneUtils$AnalyzerType "WhitespaceAnalyzer"))))
(unwind-protect
(dolist (pathname pathnames)
(let ((pathname (namestring pathname)))
(document (#"createDocument" global-document-builder image pathname)))
(#"addDocument" index-writer document))
(format T " done.~%")))
- (#"closeWriter" 'net.semanticmetadata.lire.utils.LuceneUtils index-writer))))
+ (#"closeWriter" 'LuceneUtils index-writer))))
```
+**Note**: This code won't work on current ABCL as is, because the lookup
+is disabled for for nested classes (those containing the dollar
+character). Because of this, the `AnalyzerType` class would have to be
+looked up as follows:
+
+```
+(jfield "net.semanticmetadata.lire.utils.LuceneUtils$AnalyzerType" "WhitespaceAnalyzer")
+```
+
+All in all nothing fancy, JSS takes care of a lot of typing as the names
+are all unique enough.
+
The process is simply creating the document builder and index writer,
reading all the files one by one and adding them to the index. There's
no error checking at the moment though.
written this way there's no point in creating a `WITH-OPEN-*` macro to
automatically close the writer, however, looking at the `LuceneUtils`
source this could be accomplished by directly calling `close` on the
-writer object instead.
+writer object instead - a corresponding macro might this then:
+
+```
+(defmacro with-open ((name value) &body body)
+ `(let ((,name ,value))
+ (unwind-protect
+ (progn ,@body)
+ (#"close" ,name))))
+```
It would also be nice to have auto conversion using keywords for enum
values instead of needing to look up the value manually.
```
(defun query-index (index-name pathname)
(let* ((image (read-image pathname))
- (index-reader (#"open" 'org.apache.lucene.index.DirectoryReader
- (#"open" 'org.apache.lucene.store.FSDirectory
- (#"get" 'java.nio.file.Paths index-name (jnew-array "java.lang.String" 0))))))
+ (index-reader (#"open" 'DirectoryReader
+ (#"open" 'FSDirectory
+ (#"get" 'Paths index-name (jnew-array "java.lang.String" 0))))))
(unwind-protect
- (let* ((image-searcher (new 'GenericFastImageSearcher 30 (jclass "net.semanticmetadata.lire.imageanalysis.features.global.CEDD")))
+ (let* ((image-searcher (new 'GenericFastImageSearcher 30 (find-java-class 'CEDD)))
(hits (#"search" image-searcher image index-reader)))
(dotimes (i (#"length" hits))
(let ((found-pathname (#"getValues" (#"document" index-reader (#"documentID" hits i))
- (jfield "net.semanticmetadata.lire.builders.DocumentBuilder"
- "FIELD_NAME_IDENTIFIER"))))
+ (get-java-field 'builders.DocumentBuilder "FIELD_NAME_IDENTIFIER"))))
(format T "~F: ~A~%" (#"score" hits i) found-pathname))))
- (#"closeReader" 'net.semanticmetadata.lire.utils.LuceneUtils index-reader))))
+ (#"closeReader" 'LuceneUtils index-reader))))
```
To note here is that the `get` call on `java.nio.file.Paths` took way
Lisp":
```
-(import '(javax.imageio.ImageIO java.io.FileInputStream))
-
(defun read-image (pathname)
(ImageIO/read (FileInputStream. pathname)))
```
formerly legal Lisp names.
```
-(import '(javax.imageio.ImageIO java.io.FileInputStream))
-
(defun read-image (pathname)
(#"read" 'ImageIO (new 'FileInputStream pathname)))
```
-This way is the middle ground that would be possible. The one addition
-to the current JSS system is the importing of Java names and
-corresponding interaction with the FFI.
+This way is the middle ground that we have now. The one addition here
+could be that name lookup is done at macro expansion / compilation time,
+so they are fixed one step before execution, whereas at the moment the
+JSS reader macro will allow for very late bound name lookup instead.
The similarity with CLOS would be the use of symbols for class names,
but the distinction is still there, since there's not much in terms of
want the Java side to receive a Lisp object. Having a special variable
to *disable* conversion might be enough for these purposes.
+If we were to forego the nice properties of JSS by requiring a function
+form, the following would be another option:
+
+```
+(defun read-image (pathname)
+ $(read 'ImageIO (new 'FileInputStream pathname)))
+```
+
+Where `$(...)` would be special syntax indicating a Java method call.
+Of course the exact syntax is not very relevant, more importantly static
+properties could be used to generate a faster, early bound call by
+examining the supplied arguments as a limited form of type inference.
+
## Summary
After introducing the necessary steps to start using ABCL with "native"