使用clojure生成java bean
在clojure中给定一个向量,有没有一种方法可以轻松地生成java bean?例如,给定如下向量:使用clojure生成java bean,java,clojure,interop,Java,Clojure,Interop,在clojure中给定一个向量,有没有一种方法可以轻松地生成java bean?例如,给定如下向量: [ String :key1 Integer :key2 ] public class NotSureWhatTheTypeWouldBeHere { private String key1; private Integer key2; public NotSureWhatTheTypeWouldBeHere() {} public NotSu
[
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.
}
我希望它生成如下代码:
[
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编写的库。这意味着返回值应该是JavaBean(我知道它们不必是,但我希望它们是)。一种方法是用java定义模型,然后使用clojure的普通java互操作在clojure代码中填充模型,但我喜欢简洁的clojure向量(或映射)扩展为(详细的)java bean的想法 我想这应该是可能的,但我不确定您是否完全理解Clojure中的键(可能只是我误读了您的示例代码) 像
:name
这样的键属于clojure.lang.Keyword
类型,而不是String
或Integer
等(您通常也不会在clojure中声明类型)。它们通常在映射(使用{}语法)中用于检索值,例如,以下代码从映射中检索与:key2
相关的值{:key1“hello”,:key2 4}
(get {:key1 "hello", :key2 4} :key2)
4
我不确定您的示例是否试图说您的:key1
与字符串
值关联,而:key2
与整数
值关联,或者您是否认为:key1
是字符串
类型。如果是前者,可能需要使用地图而不是向量
很抱歉,我认为我对Java bean或您的用例了解不够,无法提供更多帮助。我认为您的Java代码无法很好地处理自动生成的Java bean兼容类。您需要在Java端至少有一个接口,以了解Clojure将返回什么。否则,您将不得不恢复到:
Object result = callClojureLib(params);
然后,无论实际结果是否实现了JavaBean契约,您的Java代码都必须执行各种反射向导才能调用setter,因为您缺少类规范
解决这个问题的另一种方法是使用java.util.Map
接口作为java和Clojure worlds之间的契约。这样,您就可以使用普通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,但可以创建两个方法来获取和设置持有状态的atom。+1使用java.util.Map作为接口类。我进一步建议使用字符串作为键:在Clojure端,字符串和关键字一样有效,但Java API用户更容易找到它们……这可能是正确的答案,但它忽略了一点,即我特别不希望Java端有映射。我有大量的java代码,即服务、dao和一堆模型对象。我希望我可以重写成clojure,这样可以动态生成模型对象(从而大大减少代码大小)。从客户机的角度来看,代码与原始java代码没有什么不同。我建议您从客户机java代码的示例开始,然后尝试找到一个通用接口,该接口可以描述您需要的所有情况,并且可以从Clojure中
具体化
。问题实际上在于,在没有与Java方签订通用合同的情况下,试图动态生成JavaBean。