If you're willing to use Spring you can create Clojure-based Spring Beans [1] and let Spring inject (autowire) them into your Java-based Spring-Beans. And if you like you could use Spring just as a factory that you invoke. I would still define interfaces (that you want to use from Java) in Java, so that IDE autocompletion, generics etc. work as excepted. HTH Henrik
[1] https://github.com/henrik42/spring-break Example: <bean id="load_script_code" class="clojure.lang.Compiler" factory-method="loadFile"> <constructor-arg value="src/main/clojure/no-namespace-scripts/script-code.clj" /> </bean> Am Montag, 10. Juni 2019 17:34:25 UTC+2 schrieb eglue: > > > I find the glue code is actually small in practice (I've done a couple > of real systems this way). This particular example is a little weird > because it's just making a domain object, but generally you're writing the > glue to provide a factory method for a facade. Below the facade, the > Clojure code can make new objects just fine, so you're staying in Clojure > for the rest of it. > > Very helpful, thanks! > > On Monday, June 10, 2019 at 8:20:44 AM UTC-5, Alex Miller wrote: >> >> >> On Mon, Jun 10, 2019 at 12:04 AM eglue <atd...@gmail.com> wrote: >> >>> This is great, Alex, thanks. (Sorry, I deleted from underneath you and >>> reposted to fix the title before I saw your reply...) >>> >>> The latter option, writing interfaces and classes in Java and calling w/ >>> the glue code is a great option. >>> >>> However one big motivator for people moving from Java to langs like >>> Scala and Kotlin is being able to implement those bean/record types, eg, >>> with such little fanfare & boilerplate (eg in Clojure, using defrecord is >>> so concise). >>> >> >> The problem with wanting the Clojure-y version from Java is that those >> interfaces are generic and weird from the Java side. So either you get >> bean-like code familiar to Java users or generic collection/keyword >> interfaces that will be weird to use from Java. I heard your goal as "be >> friendly from Java", which means, making bean-like interfaces. On the >> Clojure side, it's pretty easy to macro-ize the creation of those over >> defrecords or whatever, so it could still be a lot less macro work, just >> depends how far you want to go with it. You don't get all the benefits of >> Clojure from Java; you have to be in Clojure for the many related design >> decisions to compound together. There's no magic solution to that (other >> than "just use Clojure" :). >> >> >>> And you can sometimes end up with a handful of these, so the 'glue code' >>> isn't quite so small. Also gen-class and definterface I find similarly >>> nice. >>> >> >> I find the glue code is actually small in practice (I've done a couple of >> real systems this way). This particular example is a little weird because >> it's just making a domain object, but generally you're writing the glue to >> provide a factory method for a facade. Below the facade, the Clojure code >> can make new objects just fine, so you're staying in Clojure for the rest >> of it. >> >> >>> I wonder if there's a path to improve what you're calling option #2. >>> Specifically the needing to AOT compile *everything*. It seems I should >>> only have to AOT/precompile the surface area that my Java consumer wants to >>> link with. At runtime perhaps there'd be some creative way to leave out the >>> AOT classes (which would just have been used for static-time compiling) and >>> when the JVM tries to load those classes some agent could interject and do >>> the dynamic Clojure loading? >>> >> >> Seems like you're taking the hardest path and trying to make it harder. I >> just don't see the point in running at this one, sorry. My experience is >> that the approach above works great and has none of these issues. >> >> >>> >>> >>> On Sunday, June 9, 2019 at 11:21:28 PM UTC-5, Alex Miller wrote: >>>> >>>> Looks like the title for this is backwards if I understand the intent, >>>> should be calling Clojure from Java, right? >>>> >>>> Java code is going to invoke methods on classes (that's all it knows >>>> how to do). You have several options: >>>> >>>> 1) Use the Clojure Java API to invoke the Clojure runtime - here you're >>>> leveraging the Clojure runtime's Java impl core to call into Clojure >>>> (Stu's >>>> example) >>>> 2) Use protocols, records, and/or genclass to actually produce Java >>>> classes (your example, I think). >>>> 3) Define your interface as a set of Java interfaces. Implement this >>>> interface in Clojure. You will need a small amount of glue code to provide >>>> the API impl (some kind of a factory to give you the impl of the Java >>>> interface - either written in Java or using #1). >>>> >>>> #1 is straightforward but tedious - it's really only worthwhile if you >>>> have a small amount of this code and hide the use of it. >>>> #2 has significant downsides - needing to compile everything, all >>>> methods are just going to take/return Java Objects, no javadoc on apis, >>>> etc. >>>> #3 has advantages in all those areas. You write your Java interface >>>> where you can best write it ... in Java (with Javadoc, and Java >>>> interfaces, >>>> and all the niceties Java users want). IDEs can autocomplete on the Java >>>> interfaces. You don't have to AOT - factories can reify or load protocol >>>> instances as needed as they return objects. You can even reload internal >>>> vars with a connected REPL without restarting the app. >>>> >>>> The last does take a bit of planning to set up - you need API code (in >>>> Java), and Clojure code that relies on that Java code. lein makes it >>>> pretty >>>> trivial to put those in one project and compile in that order. >>>> >>>> I pushed an example up here: >>>> >>>> https://github.com/puredanger/clojure-from-java >>>> >>>> It defines a Java interface (java/cfj/Event.java >>>> <https://github.com/puredanger/clojure-from-java/blob/master/java/cfj/Event.java>), >>>> >>>> a static helper to hook the Clojure (java/cfj/Support.java >>>> <https://github.com/puredanger/clojure-from-java/blob/master/java/cfj/Support.java>), >>>> >>>> which uses the Clojure Java API to load the Clojure instance in >>>> clj/core/cfj.clj >>>> <https://github.com/puredanger/clojure-from-java/blob/master/src/cfj/core.clj>. >>>> >>>> Just `lein uberjar` and you're done. Use the Support API from Java as any >>>> other Java class. No AOT required. >>>> >>>> >>>> >>>> On Sunday, June 9, 2019 at 9:53:56 PM UTC-5, eglue wrote: >>>>> >>>>> I've been stalking Clojure for a while but now doing it professionally >>>>> full-time (woo hoo!). >>>>> >>>>> I saw a Stuart Halloway tweet responding to someone who'd found it a >>>>> "soul-crushing, miserable experience." >>>>> >>>>> I had a similar miserable experience and figured it was just me, but >>>>> am now suspecting that's not the case. (Happy to be shown the light >>>>> however.) >>>>> >>>>> Stuart H posted https://github.com/stuarthalloway/clojure-from-java >>>>> <https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2Fstuarthalloway%2Fclojure-from-java&sa=D&sntz=1&usg=AFQjCNFxHASS9MQ07WZ5St1GE9g1WckHFg> >>>>> to >>>>> demonstrate the ease of Java consuming Clojure, but I find it far more >>>>> important to be able to *compile* Java against Clojure interfaces not >>>>> invoke it dynamically from Java....because dynamic invocation from Java >>>>> is >>>>> unwieldy to the point of it being a likely deal breaker for any Java >>>>> shop. >>>>> Dynamically loading classes and invoking methods.... c'mon, no one's >>>>> going >>>>> to ask their Java devs to do this. >>>>> >>>>> If Clojure doesn't have a good compile-time consumption story for Java >>>>> consumers, I think that's a loss. (Even if it is just providing better >>>>> docs >>>>> or archetype/bootstrap examples in this regard.) Because otherwise Java >>>>> code bases around the world could be eaten away by (compiled) Clojure >>>>> from >>>>> the inside out, giving Java dev teams enough time to be overtaken by the >>>>> miracle that is Clojure. >>>>> >>>>> Inspired by Stuart's example, I was successful in putting together a >>>>> quick build to achieve this ideal: >>>>> https://github.com/atdixon/clojure-from-java >>>>> <https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2Fatdixon%2Fclojure-from-java&sa=D&sntz=1&usg=AFQjCNG0DEccFtsm0Norw4jQ_qw-dezdZw> >>>>> >>>>> However, I have a few open questions: >>>>> >>>>> - when I tried to AOT only the public-facing clojure code that I >>>>> needed to compile against, I found out at runtime that this wasn't going >>>>> to >>>>> work. Dynamic clojure code was loading my same types into >>>>> DynamicClassLoader and when my statically-compiled, root-class-loaded >>>>> code >>>>> was getting executed the ClassCastExceptions of course were flying. So am >>>>> I >>>>> right to think that you have to AOT everything in order to do this right? >>>>> - IDE support (for me, Cursive) "works" but is non-ideal; you have to >>>>> manually compile the dependee/Clojure jar, then Cursive will let you >>>>> execute Java code against the manually aot-compiled Clojure code >>>>> - AOT producing generics/generic types doens't seem to be part of any >>>>> of this... is this a lacuna in the Clojure AOT space, are there libs that >>>>> can help here? >>>>> >>>>> This story ^^, if made easier, seems to me would boost Clojure >>>>> adoption in Java/JVM shops. >>>>> >>>>> What am I missing? >>>>> >>>>> >>>>> -- >>> You received this message because you are subscribed to the Google >>> Groups "Clojure" group. >>> To post to this group, send email to clo...@googlegroups.com >>> Note that posts from new members are moderated - please be patient with >>> your first post. >>> To unsubscribe from this group, send email to >>> clo...@googlegroups.com >>> For more options, visit this group at >>> http://groups.google.com/group/clojure?hl=en >>> --- >>> You received this message because you are subscribed to a topic in the >>> Google Groups "Clojure" group. >>> To unsubscribe from this topic, visit >>> https://groups.google.com/d/topic/clojure/aejqMwraPk8/unsubscribe. >>> To unsubscribe from this group and all its topics, send an email to >>> clo...@googlegroups.com. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/clojure/07753636-3414-481f-8836-763ca85675ce%40googlegroups.com >>> >>> <https://groups.google.com/d/msgid/clojure/07753636-3414-481f-8836-763ca85675ce%40googlegroups.com?utm_medium=email&utm_source=footer> >>> . >>> For more options, visit https://groups.google.com/d/optout. >>> >> -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/clojure/e373728d-b243-4195-b8ec-92a1b7549c0d%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.