Java Interoperability

Calling Java Code from PicoLisp

Startup

(load "@java/lib.l")

$ pil @java/lib.l +

The API

java

String

int

BigInteger

T

NIL

Boolean

(java 'cls 'T ['any ..]) -> obj

msg

cls

(java 'cls 'msg ['any ..]) -> obj

msg

obj

(java 'obj 'msg ['any ..]) -> obj

public

(public 'obj 'any ['any ..]) -> obj

any

obj

(public 'cls 'any ['any ..]) -> obj

any

cls

any

(interface 'obj 'cls|lst 'sym 'fun ..) -> obj

cls

lst

obj

obj

Examples

: (setq Sb (java "java.lang.StringBuilder" T "abc")) # Construct object -> {OOOO5276732765} : (java Sb 'append (char 44)) # Call 'append' method -> {OOOO5276732765} : (java Sb 'append 123) -> {OOOO5276732765} : (java Sb 'toString) # Convert to String -> "abc,123"

: (setq Cal (java "java.util.GregorianCalendar" T)) -> {OOOO24137612300}

: (show Cal) {OOOO24137612300} ({OOOO7764433062} . "java.util.GregorianCalendar") BC 0 BCE 0 AD 1 CE 1 EPOCH_OFFSET 719163 EPOCH_YEAR 1970 MONTH_LENGTH (31 28 31 30 31 30 31 31 30 31 30 31) LEAP_MONTH_LENGTH (31 29 31 30 31 30 31 31 30 31 30 31) ONE_SECOND 1000 ONE_MINUTE 60000 ONE_HOUR 3600000 ONE_DAY 86400000 ONE_WEEK 604800000 MIN_VALUES (0 1 0 1 0 1 1 1 1 0 0 0 0 0 0 -46800000 0) LEAST_MAX_VALUES (1 292269054 11 52 4 28 365 7 4 1 11 23 59 59 999 50400000 1200000) MAX_VALUES (1 292278994 11 53 6 31 366 7 6 1 11 23 59 59 999 50400000 7200000) serialVersionUID -8125100834729963327 gcal {OOOO2322434213} jcal NIL jeras NIL DEFAULT_GREGORIAN_CUTOVER -12219292800000 gregorianCutover -12219292800000 gregorianCutoverDate 577736 gregorianCutoverYear 1582 gregorianCutoverYearJulian 1582 gdate {OOOO34261410206} cdate {OOOO34261410206} calsys {OOOO2322434213} zoneOffsets (3600000 0) originalFields NIL cachedFixedDate 735631 $assertionsDisabled T -> {OOOO24137612300}

: (show '{OOOO7764433062}) {OOOO7764433062} ({OOOO376765756} . "java.util.Calendar") ... : (show '{OOOO376765756}) {OOOO376765756} ({OOOO1514706475} . "java.lang.Object") -> {OOOO376765756}

: (java (java Cal 'getTimeZone) 'getDisplayName) # Get the time zone -> "Central European Time" : (java Cal 'get (public Cal 'HOUR_OF_DAY)) # Current hour -> 10 : (time (time)) # Check it -> (10 34 0) : (java Cal 'get (public Cal 'WEEK_OF_YEAR)) # Current week -> 6 : (week (date)) # Check it -> 6

: (java Cal 'get (public Cal 'YEAR)) # Current year -> 2015 : (java Cal 'set (public Cal 'YEAR) 2020) # Modify it -> NIL : (java Cal 'get (public Cal 'YEAR)) -> 2020

Simple GUI Examples

(let (Frame (java "javax.swing.JFrame" T "Bye-Frame") Button (java "javax.swing.JButton" T "OK") ) (java Frame 'add "South" Button) (java Button 'addActionListener (interface Button "java.awt.event.ActionListener" # When button is clicked, 'actionPerformed '((Ev) (bye)) ) ) # Exit PicoLisp (java Frame 'setSize 100 60) (java Frame 'setVisible T) )

interface

(de animate (Str) (let (Txt (chop Str) Dir 1 Rev (dec (length Txt)) Frame (java "javax.swing.JFrame" T "Animation") Label (java "javax.swing.JLabel" T Str) ) (java Label 'addMouseListener (interface Label "java.awt.event.MouseListener" 'mouseClicked '((Ev) (setq Dir (if (= 1 Dir) Rev 1))) ) ) (java Frame 'add Label) (java Frame 'pack) (java Frame 'setVisible T) (until (key 250) (java Label 'setText (pack (do Dir (rot Txt)))) ) (java Frame 'dispose) ) )

(animate "Hello World! ")

Inline Java Code

javac

### RosettaCode Image Noise ### (javac "ImageNoise" "JPanel" NIL "java.util.*" "java.awt.*" "java.awt.image.*" "javax.swing.*" ) int DX, DY; int[] Pixels; MemoryImageSource Source; Image Img; Random Rnd; public ImageNoise(int dx, int dy) { DX = dx; DY = dy; Pixels = new int[DX * DY]; Source = new MemoryImageSource(DX, DY, Pixels, 0, DX); Source.setAnimated(true); Img = createImage(Source); Rnd = new Random(); } public void paint(Graphics g) {update(g);} public void update(Graphics g) {g.drawImage(Img, 0, 0, this);} public void draw() { for (int i = 0; i < Pixels.length; ++i) { int c = Rnd.nextInt(255); Pixels[i] = 0xFF000000 | c<<16 | c<<8 | c; } Source.newPixels(); paint(getGraphics()); } /**/ (de imageNoise (DX DY Fps) (let (Dly (/ -1000 Fps) Frame (java "javax.swing.JFrame" T "Image Noise") Noise (java "ImageNoise" T DX DY) Button (java "javax.swing.JButton" T "OK") ) (java Frame 'add Noise) (java Frame 'add "South" Button) (java Button 'addActionListener (interface Button 'java.awt.event.ActionListener 'actionPerformed (curry (Dly Frame) (Ev) (task Dly) (java Frame 'setVisible NIL) #{? (java Frame 'dispose) }# ) ) ) (java Frame 'setSize DX DY) (java Frame 'setVisible T) (task Dly 0 Obj Noise (java Obj 'draw) ) ) )

javac

gcc

(imageNoise 320 240 25)

Extended Data Formats

cons





1 for Byte

2 for Char

3 for Short

4 for Integer (default, usually not needed)

(default, usually not needed) 8 for Long

9 for BigInteger





double

: (scl 6) -> 6 : (round (public "java.lang.Math" 'PI)) -> "3.142" : (round (java "java.lang.Math" 'pow (-6 . 4.0) (-6 . 3.0))) -> "64.000"

How It Works

java

public

interface

reflect

jre

$ (cd java; ./mkJar)

jre

*Java

(pipe (exec 'java "-cp" Path "Reflector" Rqst Rply))

Path

*Java

Rqst

Rply

mkfifo

interface

task

Java

reflect

*Java

jre

(ext (car *Java) (out (cdr *Java) (pr (rest))) (in (cdr *Java) (rd)) ) )

Why not interface PicoLisp directly to Java? We have that already in Ersatz PicoLisp , the plain vanilla Java version of PicoLisp. It is almost trivial to port this functionality to real PicoLisp, by starting up and communicating with a Java virtual machine (JVM).For universal use I added a "java/" directory to the PicoLisp core distribution (with version 3.1.9.7). Please note that because of differences in the PLIO format of external symbols, it is fully supported only on the 64-bit version of PicoLisp.Naturally, a Java runtime (JRE), and optionally - if you want to use inline Java code (see below) - a development kit (JDK) should be installed.An application needs to callFor the following experiments, you can start PicoLisp asJust as in ErsatzLisp,is the central function. The syntax is very similar, with one major difference: The Java library distinguishes more strictly between internal and transient symbols. Methods are recognized when they are passed as internal symbols, while class names should be transients.The primitive types are passed directly. This means that transient symbols on the PicoLisp side map toon the Java side, and PicoLisp numbers map - depending on the size - toor. Other number types see "Extended Data Formats" below. The Lisp symbolsandmap toJava Objects appear on the PicoLisp side as external symbols, like remote database objects, by making use of Java reflection and the PicoLisp *Ext mechanism. This allows transparent (read-only) access to Java objects with arbitrary Lisp functions like get edit etc.To create a new Java object (constructor call):Call a static methodfor a classCall a dynamic methodfor an objectLike in ErsatzLisp,accesses public fields in Java objects or classes:returns the value of a public fieldin objectreturns the value of a public fieldin classIn both forms, the optionalarguments will in turn access corresponding fields in the object retrieved so far.To create an interface object:creates an interface, i.e. a set of methods for a class(or a list of classes), and associates it with the object. Note that theargument does not in ErsatzLisp.From the above article This example is a bit silly, as strings are better handled directly in PicoLisp.But a general calendar object might be useful:We can inspect it with show look at its class and superclass,or operate on itand change values:The source codes of the following three examples can also be downloaded from http://software-lab.de/javaDemo.tgz Again from the article It shows a use case forThe "Animation" task from http://rosettacode.org You can call it asIt will show a scrolling text, which reverses the scroll direction when you click on it. A key press stops it.Like in ErsatzLisp, you can embed Java Programs directly into PicoLisp code, with thefunction:is analog to thefunction in "@lib/native.l".It takes a package or class name (here "ImageNoise"), an optional "extends" (here "JPanel") and "implements" (here empty), and an arbitrary number of "import" arguments (here "java.util.*" etc.).Then all following code till a separating "/**/" line is taken as Java code, creating a file "ImageNoise.class" in the temporary (process-private) space. You can start it as. A window is shown with random image noise, and an "OK" button to close it.While integers are directly passed to/from the JVM, other number formats can be passed to the JVM aspairs consisting of an ID in the CAR and the value in the CDR. These are:If the CAR is a negative number, the value is taken as ascaled by the negated number of digits.If the argument is a list, it is passed as an array of the corresponding type to/from the JVM.See the file "@java/test.l" in the PicoLisp distribution for more examples.The top-level functionsandin "@java/lib.l" call the internal workhorseThe runtime Java code is in "@java/reflector.jar". It was built withfrom the sources in "Reflector.java" (the actual communication with PicoLisp) and "InOut.java" (a PLIO library).checks a global variable. If this variable is not set, it is assumed that the JVM is not running yet. It will be started by the lineThis runs Java with the proper classpath in, and the bidirectional file descriptor (for the pipes to standard input and from standard output of that process) is stored in, together with a fixed external symbol offset of 65535 (more below). This pipe is then used to send commands to the JVM, and receive results.Before that, two additional pipes(request) and(reply) are created as named pipes (with), and passed to the Java-call on the command line. They are used for asynchronous requests from Java back to PicoLisp, allowing the execution of Lisp code from Java (e.g. for thecallbacks).A backgroundis started to handle these requests.Then a cons pair of that external symbol offset (65535, in the CAR of) and thefunction is added to the PicoLisp system global *Ext . This allows to receive and send Java objects like remote database objects. The highest possible file number of 65535 was chosen to avoid conflicts with possibly open local and remote databases.Whenever data is received from Java (with rd ), or sent with pr , the corresponding ext -calls make handle the proper symbol offsets.Afteris initialized, subsequent calls towill only executei.e. send all arguments to Java with out ), and receive the results with in ).

http://picolisp.com/wiki/?javacode