簡體   English   中英

用clojure生成java bean

[英]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 ,而不是StringInteger等(您通常也不會在Clojure中聲明類型)。 它們通常用於映射(使用{}語法)來檢索值,例如,以下代碼從映射{:key1 "hello", :key2 4}檢索與:key2關聯的值。

(get {:key1 "hello", :key2 4} :key2)
4

我不確定你的例子是否試圖說你有:key1String 相關聯:key2Integer 相關聯,或者你認為:key1String類型。 如果是前者,可能想要使用地圖而不是矢量。

我擔心我不認為我對Java bean或你的用例有足夠的了解,以便進一步提供幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM