Better way to make init a java builder class from clojure map?

clojure gen-class
clojure proxy
clojure implement java interface
clojure defrecord
clojure reify
clojure syntax
clojure import
clojure compiler

everyone

I'm try to write a function to wrap CsvReadOptions.Builder.html in clojure .

The function will take a map like this : {:header true :locale "US"}, the function will configure the builder according to the map.

(defn reader-options [ opts ]
  (let [ b (CsvReadOptions$Builder.)]
    (cond-> b
      (contains? opts :locale ) (.locale (:locale opts))
      (contains? opts :header ) (.header (:header opts))
        true (.build ))
  )
)

Sorry if it is too much to ask, is there a better way in clojure to accomplish this ? because the key works duplicates in single line.

      (contains? opts :locale ) (.locale (:locale opts))    

Thank you again for any suggestions.


gen-class - clojure.core, MyClass with a method named mymethod, gen-class will generate an All inherited methods, generated methods, and init and main functions (see :​methods, can be referred to by their Java names (int, float etc), and classes in the java.lang a mapping from a constructor signature to a superclass constructor signature. Clojure provides aliases for primitive Java types and arrays which do not have typical representations as Java class names. The types are represented according to the specification of Java Field Descriptors. For example, byte arrays (byte-array []) have a type of "[B".


In this problem you have several factors present:

  1. Optional parameters
  2. Mutable objects
  3. Java interop

This is the reason you are getting locale and header replicated 3 times on each line. I cannot think of a straightforward way of reducing this duplication. If this was a common pattern in you application, you could write a macro (compiler extension) to make it easier. Unless this is a very frequent occurrance in your code, the cost (in complexity, documentation, misunderstandings, etc) is going to greatly exceed the benefit.

Kind of like buying a new car instead of cleaning the old car. Except in extreme circumstances, the cost is probably not worth the benefit.

;)

Clojure Programming: Practical Lisp for the Java World, Practical Lisp for the Java World Chas Emerick, Brian Carper, Christophe Map, String) constructor will call the Excep tion(String) constructor on our to the superclass's constructor are determined by the :init function we identify. We'll see shortly how these make for a useful Java API for our custom exception. gen-​class  I was talking excitedly and something just slipped out: "Clojure is a better Java than Java." As soon as I said it, I knew it was the end of the conversation. It did not go well with him. Until then, the discussion had been basically which tool was better for the job, Clojure versus Java.


You could use destructuring in let:

(let [{:keys [a b c]} {:a 1 :b false}]
  [a b c])
;; => [1 false nil]

or in function arguments:

(defn args-demo [{:keys [a b c]}]
  [a b c])
(args-demo {:a 1 :b false})
;; => [1 false nil]

The issue is that it binds to nil if a specific key is not present in the map. If your values can have nil values then it won't work.

You could use some "marker" values for not present values:

(let [{:keys [a b c] :or {a ::absent b ::absent c ::absent}} {:a 1 :b nil}]
  (cond-> {}
    (not= a ::absent) (assoc :a2 a)
    (not= b ::absent) (assoc :b2 b)
    (not= c ::absent) (assoc :c2 c)))
;; => {:a2 1, :b2 nil}

You could also create a macro:

(defmacro when-key-present
  [k m & body]
  `(let [{:keys [~k] :or {~k ::not-found}} ~m]
     (when (not= ~k ::not-found)
       ~@body)))

(when-key-present a {:a false :b nil}
  (println "a was" a))
;; prints "a was false"

(when-key-present b {:a false :b nil}
  (println "b was" b))
;; prints "b was nil"

(when-key-present c {:a false :b nil}
  (println "c was" c))
;; doesn't print anything

And your function would become:

(defn reader-options [opts]
  (let [builder (CsvReadOptions$Builder.)]
    (when-key-present locale opts
      (.locale builder locale))
    (when-key-present header opts
      (.header builder header))
    (.build builder)))

You could go even beyond and create a macro that would assume that the key in opts map is identical to the builder method that should be invoked so you could then use it like:

(let [builder (CsvReadOptions$Builder.)]
  (doseq [k (keys opts)]
    (set-builder-property builder k opts)))

but this becomes more and more magical and harder to understand so I would think twice before resorting to macros.

Java Interop, All classes in java.lang are automatically imported to every namespace. from left to right, and passed to the constructor of the class named by Classname. for objects of Java types. contains? and get work on Java Maps, arrays, Strings, that implement one or more interfaces and/or extend a class with the proxy macro​. "Class." in Clojure is the same as "new Class()" in Java. Thanks to Walter Tetzner for pointing this out! -Gregg W (Nov 17, 2010) Importing Java Classes into Your Clojure Program. There is, unfortunately, one way in which Java is better than Clojure—at least in the sense that chocolate is "better" (i.e., more pleasant) than broccoli.


Practical Clojure, To do additional computation after the superclass constructor, the :post-init argument want to add two methods to your class with the following Java signatures: public int add(int a, The argument to :constructors is a map of the form {[types. From the java man pages regarding the -jar option:. When you use this option, the JAR file is the source of all user classes, and other user class path settings are ignored.


Ahead-of-time Compilation and Class Generation, To generate named classes for use by Java Each file generates a loader class of the same name with "__init" appended. use these classes directly, as use, require and load will choose between them and more recent source Specifying constructor signatures Controlling the mapping to an implementing namespace​. The Clojure debugging toolkit is an excellent tool for digging into compiled Clojure code and it demonstrates some of the ways Clojure's classes differ from classes produced from java source. It would be difficult for instance to write java code to represent Clojures closures for instance (though it's possible)


Using Clojure To Generate Java To Reimplement Clojure, Clojure already takes advantage of this, by representing maps with eight or fewer it will spill over into a PersistentHashMap, which under the covers is a 32-way tree. Unlike javac, this will format Java snippets, not just full class files: With this, I could begin to build up my data structure implementations  A map entry (key-value pair). The Map.entrySet method returns a collection-view of the map, whose elements are of this class. The only way to obtain a reference to a map entry is from the iterator of this collection-view.