[英]generate java beans with clojure
有沒有辦法在clojure中給出一個向量來輕松生成java bean? 例如,給出這樣的矢量:
[
String :key1
Integer :key2
]
我希望它生成這樣的代碼:
public class NotSureWhatTheTypeWouldBeHere {
private String key1;
private Integer key2;
public NotSureWhatTheTypeWouldBeHere() {}
public NotSureWhatTheTypeWouldBeHere(String key1, Integer key2) {
this.key1 = key1;
this.key2 = key2;
}
public void setKey1(String key1) {
this.key1 = key1;
}
public String getKey1() {
return this.key1;
}
public void setKey2(Integer key2) {
this.key2 = key2;
}
public String getKey2() {
return this.key2;
}
// and equals,hashCode, toString, etc.
}
對於上下文,我想編寫一個用java編寫但是調用用clojure編寫的庫的應用程序。 所以這意味着返回值應該是java bean(我知道它們不一定是,但我希望它們是)。 一種方法是在java中定義模型,然后使用clojure的普通java互操作來填充clojure代碼中的模型,但我喜歡簡化的clojure向量(或映射)擴展到(詳細的)java bean的想法。
我不認為您的Java代碼可以很好地與自動生成的Java bean兼容類一起使用。 你需要在Java端至少有一個接口,以便了解Clojure將返回什么。 沒有它,你將不得不恢復:
Object result = callClojureLib(params);
然后,無論實際結果是否實現Java bean契約,您的Java代碼都必須執行各種反射操作才能調用setter,因為您缺少類規范。
解決該問題的另一種方法是使用java.util.Map
接口作為Java和Clojure世界之間的契約。 這樣,您可以使用普通的Clojure映射作為傳輸對象,因為它們可以分配給java.util.Map
:
user=> (isa? (class {}) java.util.Map)
true
當你嘗試使用它時,它可能有很多不可預見的問題,但我認為你可以從以下內容開始:
(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})
從java端使用它:
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()));
生產:
f = {:Baz "hithere", :Bar 12}
f2.equals(f) = false
f2.equals(f) = true
(f2.hashCode() == f.hashCode()) = true
請注意,您需要編譯geanbean名稱空間。 該實現使用atom來存儲所有屬性,因此請確保您理解權衡。
此外,在Clojure中工作時,您可能不想使用javabeans,但是您可以創建幾個方法來獲取和設置保持狀態的原子。
我想它應該是可能的,但我不確定你是否完全理解Clojure中的鍵(可能只是因為我誤讀了你的示例代碼)。
鍵如:name
的類型為clojure.lang.Keyword
,而不是String
或Integer
等(您通常也不會在Clojure中聲明類型)。 它們通常用於映射(使用{}語法)來檢索值,例如,以下代碼從映射{:key1 "hello", :key2 4}
檢索與:key2
關聯的值。
(get {:key1 "hello", :key2 4} :key2)
4
我不確定你的例子是否試圖說你有:key1
與String
值相關聯:key2
與Integer
值相關聯,或者你認為:key1
是String
類型。 如果是前者,可能想要使用地圖而不是矢量。
我擔心我不認為我對Java bean或你的用例有足夠的了解,以便進一步提供幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.