2015-09-13 91 views
1

我做的一個關於Clojure的REPL如下:如何使用Clojure中的interop訪問默認訪問方法?

user=> (ns clojure.lang) 
nil 
clojure.lang=> (def tran (clojure.lang.LockingTransaction.)) 
#'clojure.lang/tran 
clojure.lang=> (.getReadPoint tran) 

這給出了以下結果:

IllegalArgumentException No matching field found: getReadPoint for class clojure.lang.LockingTransaction clojure.lang.Reflector.getInstanceField (Reflector.java:271) 

現在這種方法does exist

現在我想我應該可以從REPL訪問默認訪問方法。

我的問題是:如何使用Clojure中的interop訪問默認訪問方法?

回答

2

這是可能的,但它需要一些骯髒的技巧。

有一個奇怪的圖書館,vinyasa,這使得這些技巧更容易拉動。

下面是使用這個奇怪的庫從REPL會話的成績單:

user=> (require '[vinyasa.inject :as inject]) 
nil 
user=> (inject/in clojure.core [vinyasa.reflection .> .? .* .% .%> .& .>ns .>var]) 
[] 
user=> (def locking-transaction (clojure.lang.LockingTransaction.)) 
#'user/locking-transaction 
user=> (def get-read-point (.? clojure.lang.LockingTransaction "getReadPoint")) 
#'user/get-read-point 
user=> get-read-point 
(#[getReadPoint :: (clojure.lang.LockingTransaction) -> void]) 
user=> ((first get-read-point) locking-transaction) 
nil 

這裏我們加載vinyasa,並作爲推薦的圖書館,其注入名字古怪的宏成clojure.core。使用.?宏,我們發現vm通常會阻止我們訪問的受保護方法,並通過反射獲得可用於規避VM安全性的版本。最後,我們訪問並調用我們的LockingTransaction對象上的方法,並獲得預期的返回值(nil)。

請注意,在運行時向其他名稱空間插入符號在Clojure中不被視爲正常或合意的行爲,也不繞過虛擬機保護,並且可以通過調用保護或私有方法通過反射輕鬆地對虛擬機進行段錯誤或造成非常奇怪的錯誤。

+0

「> vm通常會阻止我們訪問」... 「(如果您處於相同的命名空間中) - 您無法訪問默認訪問字段嗎? – hawkeye

+0

謝謝 - Chris Zheng是一位傳奇的Clojure程序員。 – hawkeye

+0

@hawkeye命名空間與包不相同 – noisesmith