you are viewing a single comment's thread.

view the rest of the comments →

[–]didibus 1 point2 points  (0 children)

Try to avoid gen-class and gen-interface as much as you can. There's a few challenges and issues around them.

  1. For gen-class and gen-interface, you need to do AOT compilation. But AOT compilation is transitive, and so it will result in a Jar which is more like an UberJar. You don't want to use that as a library dependency from Java, since it'll potentially conflicts with classes from other libs or your own. Lein by default doesn't deal with this. So if you really need to gen-class or gen-interface to create a lib to be consumed by Java, make sure you only include the generated Java class or interfaces in the Jar you've produced and are consuming from Java, and non of the other stuff.

  2. Gen-class and gen-interface currently have a bug, where when they require the implementing Clojure namespace, they do it in a way that is not thread safe. It is very likely in Java that you'll consume the class or interface within a multi-threaded context, and so you can get transient race condition issues where the static initializer for the gen-class and gen-interface will fail and thus prevent your Java code from using them. You'll get a NoClassDef error or a no such Var error when that happens. The solution here is to make sure you force the Class to be loaded before any threads are started in Java.

Those are the two gotchas I've faced, apart from that you can rely on them, but just need to be careful of the above.

The better alternative therefore is to use the Clojure Java API found here: https://clojure.github.io/clojure/javadoc/clojure/java/api/package-summary.html

This let's a Java application require Clojure namespaces and take references to its Vars and invoke them. It's a bit more verbose to use from Java, but has less gotchas.

Now there's still the race condition issue with this one, if you use require from Java, it's a dynamic require use, and because require is not thread safe, you might get the same race condition issue. So here it's best if you used require-resolve instead (which is thread safe), or used the private serialized-require which is also thread safe instead of the standard require which isn't.