diff options
author | Rich Hickey <richhickey@gmail.com> | 2009-03-16 15:36:16 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2009-03-16 15:36:16 +0000 |
commit | c44a65c3c71a3b5e86a2c131384005d6bb27b54d (patch) | |
tree | d2ef4f4687c84df59b8d1c6cfa18891bc88d0aa0 /src | |
parent | eac2f449af3e410f23d1ee6ca5ead6a1291de5a9 (diff) |
fixed proxy: inheriting a method from more than one iface [issue 93], patch from cgrand
Diffstat (limited to 'src')
-rw-r--r-- | src/clj/clojure/core_proxy.clj | 35 |
1 files changed, 25 insertions, 10 deletions
diff --git a/src/clj/clojure/core_proxy.clj b/src/clj/clojure/core_proxy.clj index 120ffbf3..33f91a42 100644 --- a/src/clj/clojure/core_proxy.clj +++ b/src/clj/clojure/core_proxy.clj @@ -19,6 +19,12 @@ (defn method-sig [#^java.lang.reflect.Method meth] [(. meth (getName)) (seq (. meth (getParameterTypes))) (. meth getReturnType)]) +(defn- most-specific [[rtypea :as a] [rtypeb :as b]] + (cond + (isa? rtypea rtypeb) a + (isa? rtypeb rtypea) b + :else (throw (Exception. "Incompatible return types")))) + (defn proxy-name {:tag String} [#^Class super interfaces] @@ -158,20 +164,32 @@ (if (seq meths) (let [#^java.lang.reflect.Method meth (first meths) mods (. meth (getModifiers)) - mk (method-sig meth)] + mk (method-sig meth) + sig (pop mk) + rtype (peek mk)] (if (or (considered mk) (not (or (Modifier/isPublic mods) (Modifier/isProtected mods))) ;(. Modifier (isPrivate mods)) (. Modifier (isStatic mods)) (. Modifier (isFinal mods)) (= "finalize" (.getName meth))) - (recur mm (conj considered mk) (next meths)) - (recur (assoc mm mk meth) (conj considered mk) (next meths)))) + (recur mm (conj considered sig) (next meths)) + (recur (assoc mm sig [rtype meth]) (conj considered sig) (next meths)))) [mm considered]))] (recur mm considered (. c (getSuperclass)))) - [mm considered]))] + [mm considered])) + ifaces-meths (apply merge-with most-specific + (for [#^Class iface interfaces #^java.lang.reflect.Method meth (. iface (getMethods))] + (let [msig (method-sig meth)] + {(pop msig) [(peek msig) meth]}))) + [mm ifaces-meths] (reduce (fn [[mm ifaces-meths] [msig [rtype meth] :as iface-meth]] + (if-let [[rt m] (mm msig)] + [(if (isa? rt rtype) mm (assoc mm msig iface-meth)) + (dissoc ifaces-meths msig)] + [mm (if (considered msig) (dissoc ifaces-meths msig) ifaces-meths)])) + [mm ifaces-meths] ifaces-meths)] ;add methods matching supers', if no mapping -> call super - (doseq [#^java.lang.reflect.Method meth (vals mm)] + (doseq [[_ #^java.lang.reflect.Method meth] (vals mm)] (gen-method meth (fn [#^GeneratorAdapter gen #^Method m] (. gen (loadThis)) @@ -184,13 +202,10 @@ (. m (getDescriptor))))))) ;add methods matching interfaces', if no mapping -> throw - (doseq [#^Class iface interfaces] - (doseq [#^java.lang.reflect.Method meth (. iface (getMethods))] - (let [msig (method-sig meth)] - (when-not (or (contains? mm msig) (contains? considered msig)) + (doseq [[_ #^java.lang.reflect.Method meth] (vals ifaces-meths)] (gen-method meth (fn [#^GeneratorAdapter gen #^Method m] - (. gen (throwException ex-type (. m (getName))))))))))) + (. gen (throwException ex-type (. m (getName)))))))) ;finish class def (. cv (visitEnd)) |