Pumphouse Pumphouse - 16 days ago 5
Java Question

Have clojure generate a java class which is used like a builder pattern

I'm trying to use clojure to build a java library. I'd like for the class to conform to java norms, meaning I'd expect the builder pattern to be the most intuitive. The libraries using it would call it like so

String actualHtml =
builder
.setTitle("Pizza Time")
.setProperty(n)
.setProperty(n+1)
.build();


With a weird compilation step, I can get this to compile by erasing the return value in each method, compiling, then adding them and compiling again.....but I'd like to know if there is a more standard approach.

(ns scorecard.core
(:gen-class
:name scorecard.Builder
:state state
:init init
:methods [[setTitle [String] scorecard.Builder ]
[[setProperty [String] scorecard.Builder ]
[build [] String ]]))


The above will fail with

Exception in thread "main" java.lang.ClassNotFoundException: scorecard.Builder, compiling:(scorecard/core.clj:1:1)


If I remove the return values compile, then compile again it works. I tried to add a precompile profile but the dependency is in the same file with the :gen-class method.

:profiles { :precomp {
:source-paths ["src/scorecard"]
:aot [parser.ast] } })


Is there a way that I can declare a return value which will return the class itself that will not throw an error?

Answer

This is a known bug

This is how I solved it in my class file add the gen-class twice

   (:gen-class
   :name scorecard.Builder)

   (:gen-class
    :name scorecard.Builder
    :state state
    :init init
    :methods [[setTitle [String] scorecard.Builder ]
    [build [] String ]])

Then in my project.clj file add the prep-task to precompile. This allows you to run tests against the class.

  :prep-tasks [["compile" "scorecard.core"]
               "javac" "compile"]
Comments