This answer to a very old question about Clojure-Java interop explains how to use gen-class
with the :state
and :init
keywords to create a single public instance variable accessible from Java. This is enough if you only need one piece of data to be available to Java classes, or if you can require the Java classes to use accessor functions that read, for example, a map stored in the state variable. This method also allows the data to change, e.g. by storing atom
s in the state variable.
What if I want to create more than one instance variable that's directly readable in a Java class? Is this possible? For example, I can compile the following files and execute the Bar
class, and see the value 42 of foo.bar
printed out.
Foo.clj:
(ns students.Foo
(:gen-class
:name students.Foo
:state bar
; :state baz
:init init))
(defn -init
[]
[[] 42])
Bar.java:
package students;
public class Bar {
public static void main(String[] args) {
Foo foo = new Foo();
System.out.println(foo.bar);
// System.out.println(foo.baz);
}
}
If I uncomment the baz
lines, Bar.java won't compile--the compiler seems to randomly create either bar
or baz
as the state variable for Foo
, so only one of them is available to Bar
. And in any event, I don't see how to initialize both bar
and baz
using an init
function.
The gen-class
macro does not support defining more than one public field. You have to use the defrecord
macro or the deftype
macro instead.
(defrecord Foo [bar baz])
Unfortunately, both the defrecord
macro and the deftype
macro does not prepare a way to define their constructors. So, where initializing multiple instance variables is mandatory, there is no shame in writing a Java class in Java.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With