2012-03-17 3 views
7

클로저에 벡터가있는 자바 빈을 쉽게 생성 할 수있는 방법이 있는가? 예를 들어 다음과 같은 벡터를 주어진 :은 클로저로 java beans를 생성한다

[ 
    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. 
} 

, 나는 자바로 작성된 응용 프로그램을 작성하고 싶습니다을하지만, clojure로 쓰여진 라이브러리를 호출합니다. 그래서 반환 값은 자바 빈이어야합니다 (나는 그들이 필요는 없다는 것을 알고 있지만 그것들을 원합니다). 한 가지 방법은 자바에서 모델을 정의한 다음 clojure의 일반적인 Java interop을 사용하여 클로저 코드로 모델을 채우는 것이지만 간결한 클로저 벡터 (또는 맵)를 (자세한 정보) 자바 빈으로 확장하는 아이디어를 좋아한다.

답변

3

자바 코드가 자동으로 생성 된 Java bean 준수 클래스에서 제대로 작동하지 않을 것이라고 생각합니다. 에는 Clojure가 반환 할 내용을 이해하기 위해 Java 측에서 최소한 하나의 인터페이스가 있어야합니다. 실제 결과는 자바 빈 계약을 구현하는 경우 Java 코드가도를 호출 할 수 있도록 반사 마법의 모든 종류를해야 할 것,

Object result = callClojureLib(params); 

그런 다음에 상관없이 : 그 없이는로 복귀해야합니다 setter, 클래스 스펙이 누락되었습니다.

이 문제에 대한 또 다른 접근법은 java.util.Map 인터페이스를 Java와 Clojure 세계 사이의 계약으로 사용하는 것입니다.그들은 java.util.Map에 할당 할 수 있습니다으로이 방법은, 당신은 단지, 전송 개체로 일반 Clojure의 맵을 사용할 수 있습니다

멀리 완벽한에서
user=> (isa? (class {}) java.util.Map) 
true 
+0

인터페이스 클래스로 java.util.Map을 사용하는 경우 +1. 나는 Strings를 키로 사용할 것을 제안한다. Clojure 측의 키워드와 마찬가지로 작동하지만 자바 API 사용자가 쉽게 접근 할 수있다 .... – mikera

+0

이것은 아마도 옳은 대답이지만, 특히 자바 측에서지도를 원하지 않는다. 나는 서비스, dao, 그리고 일련의 모델 객체 인 자바 코드를 가지고있다. 나는 모델 객체가 동적으로 생성 될 수 있도록 clojure로 다시 작성할 수 있기를 바랬다. (따라서 코드 크기가 엄청나게 줄어들었다.) 그리고 클라이언트 관점에서, 코드는 원래 자바 코드와 다르지 않습니다. – Kevin

+0

필자는 클라이언트 자바 코드 샘플에서 시작하여 원하는대로 시작한 다음 필요한 모든 케이스를 설명 할 수있는 공통 인터페이스를 찾고 Clojure에서 "reify"할 수 있도록하는 것이 좋습니다. 문제는 자바 측과 공통된 계약없이 즉석에서 자바 빈을 생성하려고 시도하는 것과 관련이있다. – skuro

0

나는 그것이 가능해야하지만 Clojure의 키를 완전히 이해하고 있는지는 모르겠다. (단지 내가 예제 코드를 잘못 읽고있을 수도있다.)

:name과 같은 키는 String 또는 Integer이 아닌 clojure.lang.Keyword 유형입니다 (Clojure에서는 일반적으로 형식을 선언하지 않습니다). 값을 검색하기 위해 종종 ({} 구문을 사용하는) 맵에서 사용됩니다. 예를 들어 다음 코드는 맵에서 :key2과 관련된 값을 검색합니다.

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

나는 당신의 예를 들어 당신이 Integer과 관련된 String:key2과 관련된 :key1이 있거나 생각하면 :key1 유형 String이다 말하려고하는 경우 확실하지 않다. 전자의 경우 벡터 대신지도를 사용하고 싶을 것입니다.

Java Bean 또는 사용 사례에 대해 충분히 알고 있다고 생각하지 않습니다. 특히 훨씬 더 많은 도움이됩니다.

2

당신이 그것을 사용하려고하면 아마 예상치 못한 문제를 많이 가지고 있지만, 내 생각

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())); 

가 생산 : 자바 측에서 사용

(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)) 
     [email protected](def-access-methods (keys fields)) 
     )) 

    (defbean com.test.Foo {Bar Integer Baz String What int}) 

: 당신은 같은 시작할 수

,
f = {:Baz "hithere", :Bar 12} 
f2.equals(f) = false 
f2.equals(f) = true 
(f2.hashCode() == f.hashCode()) = true 

geanbean 네임 스페이스를 컴파일해야합니다. 구현은 모든 속성을 저장하기 위해 원자를 사용하므로 트레이드 오프를 이해해야합니다.

또한 Clojure에서 작업 할 때 javabeans로 작업하고 싶지는 않지만 상태를 보유하는 아톰을 가져오고 설정하는 두 가지 메소드를 만들 수 있습니다.

관련 문제