Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/366.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
记录Clojure对Java对象的所有方法调用_Java_Debugging_Reflection_Clojure - Fatal编程技术网

记录Clojure对Java对象的所有方法调用

记录Clojure对Java对象的所有方法调用,java,debugging,reflection,clojure,Java,Debugging,Reflection,Clojure,我正在为一些Java库编写Clojure包装器。 为了帮助我调试,我想记录对特定Java对象的所有调用 在从原始Java的角度研究如何实现这一点之后,我发现了Java.lang.reflect.Proxy类和Java.lang.reflect.InvocationHandler接口 这让我发现: 小提示:我必须将java.lang.reflect.Proxy.newProxyInstance更改为java.lang.reflect/newProxyInstance,以使其在我的REPL中工作,因

我正在为一些Java库编写Clojure包装器。 为了帮助我调试,我想记录对特定Java对象的所有调用

在从原始Java的角度研究如何实现这一点之后,我发现了
Java.lang.reflect.Proxy
类和
Java.lang.reflect.InvocationHandler
接口

这让我发现:

小提示:我必须将
java.lang.reflect.Proxy.newProxyInstance
更改为
java.lang.reflect/newProxyInstance
,以使其在我的REPL中工作,因为
newProxyInstance
是一个静态方法。已提供更正版本,以便您可以剪切和粘贴它

在这个版本中,代理上的调用方法首先会起作用:

youpi.core=> (.charAt (debug-proxy "foo") 2) 
#object[java.lang.reflect.Method 0x53ce1eb0 public abstract char java.lang.CharSequence.charAt(int)] 2
=> \o
但遗憾的是,调用不接受任何参数的方法将不起作用:

youpi.core=> (.toUpperCase (debug-proxy "foo"))

IllegalArgumentException No matching field found: toUpperCase for class com.sun.proxy.$Proxy1  clojure.lang.Reflector.getInstanceField (Reflector.java:271)

java.lang.IllegalArgumentException: No matching field found: toUpperCase for class com.sun.proxy.$Proxy1
    at clojure.lang.Reflector.getInstanceField(Reflector.java:271)
    at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:315)
    at youpi.core$eval5981.invokeStatic(form-init3685547971046661105.clj:1)
    at youpi.core$eval5981.invoke(form-init3685547971046661105.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6927)
    at clojure.lang.Compiler.eval(Compiler.java:6890)
    at clojure.core$eval.invokeStatic(core.clj:3105)
    at clojure.core$eval.invoke(core.clj:3101)
    at clojure.main$repl$read_eval_print__7408$fn__7411.invoke(main.clj:240)
    at clojure.main$repl$read_eval_print__7408.invoke(main.clj:240)
    <...>
    at java.lang.Thread.run(Thread.java:745)

一个好的答案要么是修复我一直在使用的代码片段,要么是从Clojure那里提出一种实现相同目标的替代方法。

这可能通过字节码操作很容易实现。有很多工具可以帮助实现这一点,但从来没有使用过足够的工具使推荐的Java动态代理与接口而不是类一起工作。在您的示例中,调用
charAt
很好,因为它是对代理实现的
CharSequence
接口方法的调用。另一方面,调用
toUpperCase
将不起作用,因为
toUpperCase
是类
String
上的一个方法,它不是由您的代理实现的(可以说)。@glts如果我理解正确,使用这种方法只允许对作为接口约定一部分实现的方法进行日志调用。方法arity是不相关的,
(.length(调试代理“foo”)
确实工作正常。@EliZor是的。这是动态代理的一个限制,如果你想代理类,你确实必须降到我认为的字节码级别。值得一提的是,我已经在Clojure名称空间中手动编写了一系列代理函数,然后使用
Clojure.tools.trace
来处理我当前关心的问题。我仍然对更优雅的方法感兴趣。
youpi.core=> (.toUpperCase (debug-proxy "foo"))

IllegalArgumentException No matching field found: toUpperCase for class com.sun.proxy.$Proxy1  clojure.lang.Reflector.getInstanceField (Reflector.java:271)

java.lang.IllegalArgumentException: No matching field found: toUpperCase for class com.sun.proxy.$Proxy1
    at clojure.lang.Reflector.getInstanceField(Reflector.java:271)
    at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:315)
    at youpi.core$eval5981.invokeStatic(form-init3685547971046661105.clj:1)
    at youpi.core$eval5981.invoke(form-init3685547971046661105.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6927)
    at clojure.lang.Compiler.eval(Compiler.java:6890)
    at clojure.core$eval.invokeStatic(core.clj:3105)
    at clojure.core$eval.invoke(core.clj:3101)
    at clojure.main$repl$read_eval_print__7408$fn__7411.invoke(main.clj:240)
    at clojure.main$repl$read_eval_print__7408.invoke(main.clj:240)
    <...>
    at java.lang.Thread.run(Thread.java:745)
(defn- debug-print-invoke [obj proxy m args]
  (apply println m args)
  (.invoke m obj args))

(defn debug-proxy [obj]
  (java.lang.reflect.Proxy/newProxyInstance
    (.. obj getClass getClassLoader)
    (.. obj getClass getInterfaces)
    (proxy [java.lang.reflect.InvocationHandler] []
      (invoke
        ([proxy m] (debug-print-invoke obj proxy m []))
        ([proxy m args] (debug-print-invoke obj proxy m args))))))