Far from perfect and you probably have a lot of unforeseen problems when you try to use it, but I think you can start with something like:
(ns genbean) (defn -init [] [[] (atom {})]) (defn -toString [this] (str @(.state this))) (defn -equals [this other] (= @(.state this) @(.state other))) (defn -hashCode [this] (hash @(.state this))) (defn set-field [this key value] (swap! (.state this) into {key value})) (defn get-field [this key] (@(.state this) key)) (defn gen-method-defs [fields] (mapcat (fn [[name type]] [[(str "set" name) [type] 'void] [(str "get" name) [] type]]) fields)) (defn def-access-methods [fields] (mapcat (fn [field] [`(defgetter ~field) `(defsetter ~field)]) fields)) (defmacro defsetter [field] `(defn ~(symbol (str "-set" field)) [this# value#] (set-field this# ~(keyword field) value#))) (defmacro defgetter [field] `(defn ~(symbol (str "-get" field)) [this#] (get-field this# ~(keyword field)))) (defmacro defbean [bean fields] `(do (gen-class :main false :state ~'state :init ~'init :name ~bean :methods ~(gen-method-defs fields)) ~@ (def-access-methods (keys fields)) )) (defbean com.test.Foo {Bar Integer Baz String What int})
Using it from the java side:
Foo f = new Foo(); f.setBaz("hithere"); f.setBar(12); System.out.println("f = " + f); Foo f2 = new Foo(); System.out.println("f2.equals(f) = " + f2.equals(f)); f2.setBaz("hithere"); f2.setBar(12); System.out.println("f2.equals(f) = " + f2.equals(f)); System.out.println("(f2.hashCode() == f.hashCode()) = " + (f2.hashCode() == f.hashCode()));
It produces:
f = {:Baz "hithere", :Bar 12} f2.equals(f) = false f2.equals(f) = true (f2.hashCode() == f.hashCode()) = true
Note that you will need to compile the geanbean namespace. An implementation uses an atom to store all properties, so make sure you understand the tradeoffs.
Also, when working in Clojure, you probably do not want to work with javabeans, but you can create several methods to get and set the state-holding atom.
Danlebreo
source share